Skip to main content
Glama

Embers: Tabletop RPG Toolkit

Server Details

Characters, campaigns, adventures & worlds for D&D 5e/5.5e, Pathfinder, Savage Worlds, Fate, & more.

Ownership verified
Status
Healthy
Uptime
40.2% over 55 days
OAuth
Works in Glama
Last Tested
Transport
Streamable HTTP · MCP 2025-11-25
URL

TDQS

A3.7/5.0

Scored across 137 tools

Disambiguation4/5

Tools are organized by clear subsystem prefixes (imagine_, play_, vault_, and submission-related names), and most actions target distinct resources. However, within vault, several character-creation tools (create, build_pc, build_monster, clone, spawn_linked) share conceptual space and require careful reading to distinguish.

Naming Consistency4/5

Almost all tools use consistent snake_case with a subsystem prefix and verb_noun pattern. Minor deviations exist (whoami and list_rulesets lack prefixes; imagine_generate_* uses a different verb), but overall predictable.

Tool Count1/5

137 tools far exceeds the 3-15 range and even the 50+ threshold for extreme mismatch. While the toolkit spans multiple products, the sheer volume imposes high cognitive load and likely includes tools that could be consolidated.

Completeness5/5

The surface provides thorough CRUD/lifecycle coverage across submissions, imagine (worlds, adventures, pages), play (campaigns, sessions, moves, pages, friends, PBEM), and vault (characters, items, rules, spells) with few obvious dead ends. Minor gaps like a dedicated list of pending campaign invites are workaround-able.

Available Tools

137 tools
create_submissionReport a bug or request a featureAInspect

File a bug report or a feature request with Embers on the calling user's behalf. Pass type (bug or request), a short title, and a description. Optional attachments are ids from upload_submission_screenshot. Returns the created submission; the user can track it with list_my_submissions and get_submission.

ParametersJSON Schema
NameRequiredDescriptionDefault
typeYes`bug` for something broken, `request` for an enhancement.
titleYesShort title. Required.
attachmentsNoUpload ids from upload_submission_screenshot to attach. Optional, up to ten.
descriptionYesWhat happened, or what the user wants. Required.

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.5/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already mark this as non-read-only, so a create operation is expected. The description adds useful behavioral context beyond that: the submission is filed on the calling user's behalf, it returns the created submission, and the user can track it via the listed tools. No contradiction with the annotations.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Three tight sentences cover what the tool does, required inputs and the attachment source, and what happens with the result. The most important information is front-loaded before optional detail.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a 4-parameter creation tool with a full schema, required and optional fields are clear, the attachment dependency is stated, and related tracking tools are named. The only omitted items, such as auth or rate limits, are not expected for this kind of straightforward submission tool.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, so the schema carries the parameter details. The description still adds value by naming the required parameters in order and clarifying that attachments must be IDs from upload_submission_screenshot, a relationship not fully expressed in the schema.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description leads with a specific verb and resource: 'File a bug report or a feature request with Embers...' and explicitly distinguishes the two type values. This makes the tool's purpose unmistakable and sets it apart from tracking tools like get_submission and list_my_submissions.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description gives clear context for when to use it: to file a bug or request on the user's behalf. It also points to upload_submission_screenshot for attachments and to get_submission/list_my_submissions for tracking, but it does not explicitly state when not to use it or mention reply_to_submission as the follow-up alternative.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

get_submissionRead one of my submissionsA
Read-onlyIdempotent
Inspect

Read one of the calling user's submissions: the original report, its screenshots, the current status, and the activity feed (replies both ways and status changes). Pass submissionId from list_my_submissions. Another user's submission is forbidden.

ParametersJSON Schema
NameRequiredDescriptionDefault
submissionIdYesMongo `_id` of one of the caller's submissions (from list_my_submissions).

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.3/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint=true, destructiveHint=false, and idempotentHint=true, establishing the safety profile. The description adds meaningful behavioral context by specifying the exact contents returned (original report, screenshots, current status, activity feed with replies and status changes) and the access restriction. This goes beyond what annotations provide.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is a single, information-dense sentence that leads with the core purpose, then details the return contents, the source of the parameter, and the restriction. Every clause earns its place, and there is no filler or redundancy.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given there is an output schema (not shown but indicated), the description need not explain return format. It covers the scope, the contents, the parameter source, and the access constraint. For a simple read tool with one parameter, this is complete and unambiguous.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The schema already provides a complete description of submissionId ('Mongo `_id` of one of the caller's submissions (from list_my_submissions)') with 100% coverage. The description repeats the source (list_my_submissions) but adds no new semantics beyond what the schema already states, so it stays at the baseline of 3.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the verb ('Read') and the resource ('one of the calling user's submissions') and enumerates exactly what is returned (original report, screenshots, current status, activity feed). It also differentiates this from list_my_submissions by referencing it as the source of the ID, and from other submission tools (create, reply, upload) by its read-only nature.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description explicitly instructs how to obtain the parameter ('Pass `submissionId` from list_my_submissions') and includes a strong constraint ('Another user's submission is forbidden'). However, it does not explicitly contrast with alternative tools like reply_to_submission or upload_submission_screenshot, though the read-only intent is clear from the description and annotations.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

imagine_create_adventureCreate an adventureAInspect

Create a new adventure owned by the calling user. Required: name and ruleset (imagine has no app-wide ruleset default for adventures). Other fields pass through to imagine.

ParametersJSON Schema
NameRequiredDescriptionDefault
linkNoURL-safe slug. Lowercase letters, numbers, and hyphens. Imagine auto-suggests at create time when omitted.
nameYesAdventure name. Required.
imageNoHeader image URL.
levelNoRecommended character level range. Each side optional; null means unset.
worldNoOptional World _id this adventure belongs to.
activeNo
publicNo
statusNo
rulesetYesRuleset code. Required at create time; imagine has no default ruleset for adventures.
summaryNoShort summary; capped at 150 characters by imagine.
versionNo
keywordsNoComma-separated keyword string used by adventure-wide tag/search.
barImagesNoGM-curated reference images displayed in a fixed bar across the adventure (maps, handouts, NPC portraits).
partySizeNoRecommended party size range.
publisherNo
companionsNo
descriptionNoFull adventure description. Markdown supported.
imageCarouselNo
estimatedHoursNo
contentWarningsNo

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A3.8/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already convey that this is a mutating, non-destructive, non-idempotent operation, so the description does not need to repeat those. It adds useful ownership context and the no-default-ruleset caveat, but it does not disclose side effects, failure modes, or any creation-time behavior beyond that.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two sentences, no wasted words, and the most important information is front-loaded. The ownership, required fields, and ruleset caveat are all stated efficiently.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness3/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a 20-parameter create tool with nested objects, the description establishes ownership and required fields but leaves optional behavior, defaults, status semantics, and nested-object handling to the schema. The output schema and annotations help, but the description alone is only minimally complete.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters2/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The description adds essentially no parameter meaning beyond the schema: name and ruleset being required is already in the schema, and 'Other fields pass through to imagine' is vague. With 20 parameters and moderate schema coverage, the description does little to help an agent understand optional-field behavior or nested structures.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The first sentence states a specific verb ('Create'), a unique resource ('adventure'), and scoping ('owned by the calling user'), making it easy to distinguish from sibling tools like imagine_create_world and imagine_create_adventure_page. The required-field note reinforces the core action without blurring the purpose.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description clearly establishes the context: use this when creating a new adventure for the calling user, and it calls out the ruleset requirement and the lack of a default. It does not explicitly name alternatives for when not to use this tool, so it falls just short of a 5.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

imagine_create_adventure_pageCreate an adventure pageAInspect

Create a new page inside an adventure. Required: adventureId, name. Use this for scene descriptions, encounter rooms, NPC profiles, plot beats. Valid documentType values: generic, act, scene, location, character, handout, lore, appendix, map. Items and rules are NOT page types; author them in vault and reference them, not as adventure pages. Set the tags array so the page is filterable in adventure-page listings; the page's documentType is also auto-added to the searchable keyword set.

ParametersJSON Schema
NameRequiredDescriptionDefault
mapNoLocation shape: Mongo `_id` of the Map this location belongs to. Pass null to clear.
goalNo
linkNoURL-safe slug. Lowercase letters, numbers, hyphens, slashes.
nameYesPage name. Required.
tagsNoTag list. Imagine stores as a comma-separated `keywords` string.
imageNo
activeNo
mapPinNo
aliasesNo
contentNoPage body in markdown. Imagine renders this verbatim. WARNING: REPLACED wholesale on update; prefer imagine_replace_in_adventure_page for surgical edits.
detailsNoLabel/value list of arbitrary metadata pairs.
summaryNoShort page summary. Max 150 characters (matches the AdventurePage Mongoose schema's maxlength). Sibling Adventure and WorldPage summaries share the same cap; legacy World summaries cap at 255 (cross-app convention).
durationNo
parentIdNoMongo `_id` of the parent page (for tree structure).
templateNoTemplate id when authored from a template.
menuOrderNo
vaultRefsNoParticipants on the page. Each entry `{ vaultId?, type?, count?, name? }`.
adventureIdYesAdventure to add the page to.
locationKeyNo
documentTypeNoStructural type. Drives shape-specific fields.
treasureRefsNoTreasure entries. Same shape as `vaultRefs`.
outboundLinksNoAdventurePage ids this page links to. Imagine recomputes this on save when missing; explicit values override.
relationshipsNoSibling AdventurePage ids the page relates to.
worldPageRefsNoMongo `_id` list of referenced world pages.

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.3/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already establish this as a mutating, non-idempotent, non-destructive operation, and the description adds behavioral nuance beyond that: 'Set the tags array so the page is filterable' and 'documentType is also auto-added to the searchable keyword set.' It does not contradict any annotation.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is front-loaded with the core action and required fields, and most sentences earn their place by adding use cases or exclusions. The only mild redundancy is restating the documentType enum that already exists in the input schema, but it remains compact and scannable.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a 24-parameter create tool, the description covers the essentials: required fields, permitted document types, non-goals, and tag/filter behavior. The output schema covers return values and the input schema documents most optional fields, so an agent can safely select and invoke the tool; a minor gap is that omitting documentType is not addressed.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The schema covers 67% of parameters, and the description adds useful semantics for the most decision-critical ones: required adventureId/name, the valid documentType enum, and tag filtering behavior. However, it does not compensate for the several schema-undocumented optional fields such as goal, mapPin, locationKey, aliases, and menuOrder.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description leads with a specific verb and resource: 'Create a new page inside an adventure.' It reinforces scope with concrete use cases ('scene descriptions, encounter rooms, NPC profiles, plot beats') and clearly distinguishes itself from vault item/rule creation tools by stating those are NOT page types.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description explicitly says when to use the tool and gives an exclusion with routing guidance: 'Items and rules are NOT page types; author them in vault and reference them, not as adventure pages.' This tells an agent both what this tool is for and when to choose an alternative.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

imagine_create_worldCreate an imagine worldAInspect

Create a new world owned by the calling user. Required: name. Other fields (summary, description, link) pass through to imagine, which validates and assigns defaults where appropriate. Worlds do not carry a ruleset of their own; ruleset lives on the adventure(s) under the world instead.

ParametersJSON Schema
NameRequiredDescriptionDefault
linkNoURL-safe slug for the world (lowercase letters, digits, hyphens). Imagine auto-suggests at create time when omitted.
menuNoSite menu entries — label + optional link/pageId/order.
nameYesWorld name. Required.
imageNo
activeNo
publicNoWhether the world is public. Only Premium, VIP, and admin accounts can change whether a world is public; the server refuses the change from anyone else. A new world is public unless set otherwise.
faviconNo
summaryNoShort summary; capped at 255 characters. Cross-app convention (per dev-sites/AGENTS.md); the Mongoose World schema still accepts up to 500 as a legacy inconsistency being migrated, but new authoring should keep summaries under 255.
calendarNoOptional calendar definition (months[] + eras[]).
keywordsNo
showInviteNo
descriptionNoFull world description. Markdown supported.
customDomainNoOptional custom domain pointing at the world's public site.
imageCarouselNo
isExampleWorldNo

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.1/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

The description adds useful behavior beyond annotations: creation is scoped to the calling user, optional fields pass through to imagine for validation/defaulting, and worlds have no independent ruleset. The annotations already convey mutation (readOnlyHint=false), non-idempotency, and non-destructiveness, so the description builds rather than repeats.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Four sentences with no filler, front-loaded with the core action and required field. The ruleset note adds value without bloating the description, although the list of pass-through fields is partial and slightly ambiguous.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a create operation with an output schema and annotations covering safety/idempotency, the description supplies essential context: ownership, required field, validation/defaulting behavior, and world-ruleset relationship. The remaining gaps are field-level details, most of which live in the input schema, but the 15-parameter surface keeps it from fully complete.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema covers only 53% of parameters, and the description names just three optional fields (summary, description, link) beyond required name. The general 'pass through... validates and assigns defaults' clause is helpful but does not compensate for undocumented fields like image, favicon, keywords, and showInvite, leaving some parameter semantics to inference.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description opens with a specific verb ('Create'), a precise resource ('new world'), and ownership ('by the calling user'), clearly identifying the operation. It also calls out 'Required: name' and distinguishes worlds from adventures by noting the ruleset does not live on worlds.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Purpose context is clear: use this tool to create a world for the calling user. It gives an implicit exclusion by stating that worlds do not carry their own ruleset and that rulesets live on adventures, which helps route ruleset-related work to adventure tools, though it does not name a specific alternative.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

imagine_create_world_pageCreate a world pageAInspect

Create a new page inside a world. Required: worldId, name. Use this for NPCs, locations, organizations, events. Valid documentType values: generic, character, location, organization, event, lore, religion, cosmology. Items and rules are NOT page types; author them in vault and reference them, not as world pages. Set the tags array so the page is filterable via imagine_list_world_pages_by_tags; the page's documentType is also auto-added to the searchable keyword set. Pass visibility: 'gm' for a GM-only page (invisible to non-contributors: 404s, absent from lists) or visibility: 'masked' for a page that participates in lists and backlinks under maskName ('Redacted' when unset) with its real name, link, and content hidden until revealed.

ParametersJSON Schema
NameRequiredDescriptionDefault
linkNoURL-safe slug. Lowercase letters, numbers, hyphens, slashes.
nameYesPage name. Required.
tagsNoTag list. Stored as a comma-separated `keywords` string on the wire.
imageNo
activeNo
aliasesNo
contentNoPage body in markdown. Imagine renders this verbatim. REPLACED wholesale on update.
detailsNo
gmNotesNoGM-only notes attached to the page.
rulesetNo
summaryNoShort page summary; capped at 150 characters by imagine.
worldIdYesWorld to add the page to.
maskNameNoWhat non-contributors see instead of the page's name while visibility is 'masked'. Empty renders as 'Redacted'.
parentIdNoMongo `_id` of the parent world page (tree structure).
templateNo
eventDateNoOptional in-world event date for chronology-shape pages.
menuLabelNo
menuOrderNo
showInMenuNo
visibilityNoPage visibility. 'gm' pages exist only for the world's owner and contributors — every other viewer gets a 404 and the page is absent from lists, search, backlinks, and breadcrumbs. 'masked' pages participate in lists, tags, backlinks, and breadcrumbs but present maskName/maskSummary and an id-based URL to non-contributors; the real name, link, content, and aliases stay hidden until the page is flipped to public. Hidden pages are barred from the world menu. Default: 'public'.
maskSummaryNoOptional teaser non-contributors see on the masked page; the real summary and content stay hidden. Max 255 characters.
documentTypeNo
isWorldChildNo
outboundLinksNo
relationshipsNo
showBreadcrumbsNo
vaultCharacterIdNoBind this page to a vault character (for character-shape world pages).
playCampaignCharactersNo

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.9/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

It reveals non-obvious behaviors beyond the annotations: gm pages 404 for non-contributors and vanish from lists, masked pages still appear under maskName with hidden content, and documentType is auto-added to the keyword set. Since annotations only establish that this is a non-read-only, non-idempotent world operation, this behavioral detail is valuable and not contradicted.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is dense but every sentence earns its place: required fields and purpose first, then valid types, then tag behavior, then visibility semantics. Despite covering a 28-parameter tool, it avoids fluff and does not repeat parameter names for their own sake.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a create operation with complex visibility behavior and an output schema, the description covers the substantive choices an agent must make: page category, required identifiers, tag/filter behavior, and public/gm/masked visibility. The optional nested fields remain discoverable in the schema, so no critical guidance is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

With schema coverage at only 46%, the description compensates by spelling out the decision-critical parameters (required worldId and name, documentType values, tags filtering, visibility modes and maskName default). It does not explain many optional fields (parentId, outboundLinks, eventDate, menu fields, etc.), though those are less decision-critical for a create call.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

Opens with a precise verb and resource ('Create a new page inside a world'), then narrows the scope with concrete use cases (NPCs, locations, organizations, events) and an explicit list of valid documentTypes. It clearly differentiates world pages from the vault-item/rule authoring path and, by naming the world context, from adventure-page siblings.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description states exactly what the tool is for ('Use this for NPCs...') and gives an explicit when-not: 'Items and rules are NOT page types; author them in vault and reference them.' It also tells the agent to set tags for downstream filtering and explains how to achieve GM-only vs masked visibility, so an agent can decide correctly before invoking.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

imagine_delete_adventureDelete an adventureA
DestructiveIdempotent
Inspect

Soft-delete an adventure by id. The adventure is moved to the user's deleted-adventures list and can be restored from the imagine UI. Pages inside are tombstoned with it. Caller must have 'edit'. Destructive. Confirm with the user first.

ParametersJSON Schema
NameRequiredDescriptionDefault
idYesMongo `_id` of the adventure.

Output Schema

ParametersJSON Schema
NameRequiredDescription
idNo
deletedNo

TDQS

A4.5/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Even with annotations already marking destructiveHint=true and readOnlyHint=false, the description adds valuable behavioral detail: soft-delete semantics, movement to the deleted list, restoration via UI, tombstoning of pages, required permission, and the instruction to confirm with the user. This goes well beyond the annotations and gives the agent a clear model of side effects.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is compact and front-loaded: the core action appears first, followed by key behavioral consequences and usage warnings. Every sentence contributes useful information, and there is no redundancy or filler.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a one-parameter delete tool with an output schema present, the description covers the essential action, side effects, permission requirement, restore path, and safety caveat. Nothing an agent needs to invoke it correctly is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The schema already provides 100% coverage for the single `id` parameter, describing it as the Mongo `_id` of the adventure. The description adds no further parameter detail, but with full schema coverage, the baseline score of 3 is appropriate.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states a specific verb and resource: 'Soft-delete an adventure by id.' It also clarifies the deletion mode (soft-delete) and names the target resource (adventure), making it easy to distinguish from sibling tools like imagine_delete_adventure_page or imagine_delete_world.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description provides clear usage context: the caller must have 'edit', must confirm with the user first, and the operation is destructive. It also explains that the adventure is moved to a deleted-adventures list and can be restored via the UI, which gives practical guidance. It does not explicitly name an alternative tool for when-not-to-use, but the resource scoping is clear.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

imagine_delete_adventure_pageDelete an adventure pageA
DestructiveIdempotent
Inspect

Permanently delete an adventure page by id. Imagine does not soft-delete pages, so this is unrecoverable. Caller must own or have edit access on the page. Destructive. Confirm with the user first.

ParametersJSON Schema
NameRequiredDescriptionDefault
idYesMongo `_id` of the adventure page.

Output Schema

ParametersJSON Schema
NameRequiredDescription
idNo
deletedNo

TDQS

A4.5/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Description clearly discloses irreversibility ('unrecoverable', 'does not soft-delete'), access requirements, and destructiveness. This adds meaningful context beyond the destructiveHint and idempotentHint annotations, especially emphasizing the need for user confirmation.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Three short, information-dense sentences with no filler. The main action is front-loaded, followed by critical irreversibility, access, and safety guidance. Every sentence earns its place.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a one-parameter destructive operation with output schema presentfallback, the description covers the essential behavioral aspects: what it does, irreversibility, access requirements, and user-confirmation requirement. Nothing an agent needs to call correctly is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%: the only parameter 'id' is fully described as a Mongo _id. The description adds only 'by id', which repeats the schema. No additional parameter meaning is necessary, so baseline 3 is appropriate.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb (delete) and resource (adventure page by id). The phrase 'Permanently delete' plus 'does not soft-delete' distinguishes this from similar delete tools for other resources and from update tools.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Provides explicit context: caller must own or have edit access, and should confirm with the user first. It does not explicitly name alternatives or exclusion conditions, but the prerequisites and confirmation guidance make usage conditions clear.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

imagine_delete_worldDelete an imagine worldA
DestructiveIdempotent
Inspect

Soft-delete a world by id. The world is moved to the user's deleted-worlds list and can be restored from the imagine UI. Pages and adventures inside are tombstoned with it. Caller must have 'edit' access. Destructive. Confirm with the user first.

ParametersJSON Schema
NameRequiredDescriptionDefault
idYesMongo `_id` of the world.

Output Schema

ParametersJSON Schema
NameRequiredDescription
idNo
deletedNo

TDQS

A4.5/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

The annotations already carry destructiveHint=true, readOnlyHint=false, idempotentHint=true, and openWorldHint=true. The description adds meaningful behavioral context beyond those flags: soft-delete rather than hard delete, the deleted-worlds list side effect, restorability from the UI, child tombstoning, and the edit permission requirement. No contradiction exists.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Four short sentences deliver the core action, side effects, access requirement, and a safety caution without redundancy. The most important facts are front-loaded, and every sentence adds useful information.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

The definition fully covers what happens, what else is affected, who may call it, and the required user confirmation. With a single parameter, a well-documented schema, and the presence of an output schema, nothing essential is missing for an agent to select and invoke the tool correctly.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100% and the single parameter already has a clear description as the Mongo `_id` of the world. The description only repeats 'by id' without adding format, source, or validation details, so it doesn't add much beyond the schema. This meets the baseline for high schema coverage.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description uses a specific verb ('soft-delete'), a clear resource ('a world by id'), and precise scope ('the world is moved to the user's deleted-worlds list'). It also distinguishes this from sibling delete tools by noting pages and adventures are tombstoned with it, so an agent can tell it apart from imagine_delete_adventure and imagine_delete_world_page.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It gives clear usage context: the caller needs 'edit' access, the operation is destructive, and the user must confirm first. It doesn't explicitly name alternatives or state when not to use it, but the soft-delete/restore framing plus the sibling list makes the appropriate usage reasonably clear.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

imagine_delete_world_pageDelete a world pageA
DestructiveIdempotent
Inspect

Soft-delete a world page by id. The page is moved to the world's trash, keeps its link and aliases reserved, and can be restored from the imagine UI for 45 days before it is purged permanently. Caller must own or have edit access on the page. Destructive. Confirm with the user first.

ParametersJSON Schema
NameRequiredDescriptionDefault
idYesMongo `_id` of the world page.

Output Schema

ParametersJSON Schema
NameRequiredDescription
idNo
deletedNo

TDQS

A4.6/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already indicate destructiveHint=true, but the description adds crucial context: the page moves to trash, keeps link and aliases reserved, restore window of 45 days, and permanent purge after. This goes beyond annotations by clarifying the soft-delete nature, which is essential for the agent to know the action is reversible. Slight deduction for not specifying exact response format, but the description is behaviorally rich.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is a compact paragraph of four sentences, each with a purpose: what it does, what happens after, who can call it, and the safety warning. It front-loads the key actionable verb 'soft-delete' and does not waste words.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the tool is simple with one parameter, the description covers the action, outcome, permissions, reversibility, and safety confirmation. It doesn't describe return values, but there is an output schema (though its content is not provided in the context), so the description needn't. It also doesn't mention error conditions, but for a delete tool this is not critical. Overall, it is nearly complete.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100% and the schema describes the 'id' parameter as 'Mongo _id of the world page.' The description doesn't add much about the parameter, but since the schema is complete, baseline is 3. Credit for the description's phrase 'by id' which reinforces the parameter's role, but most semantic weight is on the schema. Thus 4 is justified for not needing more.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the verb (soft-delete), the resource (world page by id), and the key behavioral nuance (soft-delete vs delete). It distinguishes itself from sibling delete tools like imagine_delete_world and imagine_delete_adventure_page by specifying 'world page' and the soft-delete mechanism.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explicitly states when to use: caller must own or have edit access, and confirms the user before use. It also implies when not to use by contrasting with other delete tools (which likely do hard deletes) via the soft-delete detail. It provides clear prerequisites and safety steps.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

imagine_generate_draconic_nameGenerate draconic namesA
Read-only
Inspect

Generate dragon names using the harsh phonetics of the Draconic tongue. Returns an array of names.

ParametersJSON Schema
NameRequiredDescriptionDefault
countNoHow many names to generate (1–50). Defaults to 5.
lengthNoPreferred name length. Defaults to medium.
includeEpithetNoAppend a draconic epithet. Defaults to false.

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A3.9/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint=true and destructiveHint=false, so the agent knows this is a safe read/generation operation. The description adds the behavioral trait that it returns an array of names, which is useful. However, it does not disclose details like randomness, uniqueness, or whether the same input yields different outputs, which would be valuable for a generation tool. The description does not contradict annotations.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is two sentences and front-loads the core purpose. The second sentence about the return type is useful but could be considered redundant given the output schema exists. Still, it is concise and every sentence earns its place.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the tool's simplicity, the output schema, and the annotations covering safety, the description is nearly complete. It could mention that the tool is non-deterministic or that names are randomly generated, but for a simple name generator with fully documented parameters, the current description is adequate.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so the schema already documents all three parameters (count, length, includeEpithet) with descriptions and defaults. The description adds no additional parameter-level meaning beyond what the schema provides. Baseline 3 is appropriate because the schema does the heavy lifting.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description uses a specific verb ('generate') and resource ('draconic names'), and the title 'imagine_generate_draconic_name' is clearly reflected. It distinguishes itself from sibling tools like imagine_generate_npc by focusing on name generation, and the description's mention of 'harsh phonetics of the Draconic tongue' adds flavor that clarifies the resource.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description implies a creative-generation use case, and the sibling list shows many other generation tools (e.g., imagine_generate_npc, vault_build_monster), but the description does not explicitly state when to use this tool versus alternatives. It is clear enough for an agent to infer that this is for generating draconic names, not NPCs or other entities, but it lacks explicit when/when-not guidance.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

imagine_generate_npcGenerate an NPCA
Read-only
Inspect

Generate a random NPC with personality, occupation, and (optionally) a secret. Returns an NPC object.

ParametersJSON Schema
NameRequiredDescriptionDefault
includeSecretNoInclude a hidden secret for the NPC. Defaults to true.

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A3.8/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint=true, destructiveHint=false, and idempotentHint=false. The description adds useful context by noting the output is a random NPC object and that a secret may be included. It does not contradict the annotations, though it adds only modest behavioral detail beyond what annotations convey.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

A single sentence communicates the tool's purpose, contents, optionality, and return type with no filler. Every element earns its place, and the core action is front-loaded.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a simple tool with one optional parameter, full schema coverage, an output schema, and safety annotations, the description is sufficiently complete. It lacks explicit usage guidance or alternatives, but nothing essential to invoking it correctly is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, and the single parameter includeSecret already has a clear description with its default value. The main description's phrase '(optionally) a secret' adds no meaningful information beyond the schema, so the baseline of 3 applies.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states a specific action ('Generate'), a clear resource ('a random NPC'), and the key content fields (personality, occupation, optional secret), plus the return type. This clearly distinguishes it from sibling tools like vault_create_character or imagine_generate_draconic_name, even without explicitly naming them.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The intended use is implied: call this when you need a random NPC with personality and occupation. However, it does not mention alternatives or exclusion criteria, such as when to use vault_build_pc/vault_create_character for a hand-crafted character instead. The context is clear but not explicit.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

imagine_get_adventureGet an adventureA
Read-onlyIdempotent
Inspect

Fetch one adventure by id with its settings, ruleset, recommended level, and any user-linked play campaigns. The campaign link is informational only and is set by the user; imagine and play do not auto-sync state between them. If the adventure is one part of a series, parent is populated as { _id, name, link, active } — use imagine_list_adventure_parts on the parent id to see the sibling parts. Caller must have at least 'view' access, with one exception: on a PRIVATE adventure with linked play campaigns, a caller who is a member (owner or accepted player) of one of those campaigns gets a minimal recaps-only shape instead of a 403 — { _id, name, link, image, recapsOnly: true, hasLinkedCampaigns: true }, enough to call imagine_get_adventure_recaps, none of the adventure content. Non-owner viewers of public adventures get a hasLinkedCampaigns boolean in place of the stripped playCampaignIds.

ParametersJSON Schema
NameRequiredDescriptionDefault
idYesMongo `_id` of the adventure.

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.7/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already mark readOnly/idempotent/non-destructive, and the description adds the permission exception (private adventure + campaign member => recaps-only 200 instead of 403) and shape variations (`recapsOnly`, `hasLinkedCampaigns` vs `playCampaignIds`). It also clarifies the informational campaign-link behavior, which is not visible in annotations.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is long but every clause carries a distinct fact: payload, campaign non-sync, parent-series handling, and the auth exception. The main action is front-loaded, with edge-case detail following in a logical order.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With a one-parameter schema and an output schema present, the description covers all call-relevant context: access requirements, exceptions, related-tool routing, and linked-campaign behavior. No critical gap remains for an agent to invoke it correctly.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The single `id` parameter is already described in the schema as a Mongo `_id` with minLength 1 (coverage 100%), so the description has little left to add. It reinforces that the operation is by-id and mentions `parent` ids, but does not alter or extend the schema semantics.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description opens with a specific verb+resource: 'Fetch one adventure by id,' and enumerates the payload components (settings, ruleset, recommended level, linked play campaigns). It clearly differentiates from the sibling list/recap tools, and the parent-series clause names the exact sibling for related parts.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It explicitly routes to imagine_list_adventure_parts when a parent is populated, and notes the minimal shape is 'enough to call imagine_get_adventure_recaps.' It also warns that imagine and play do not auto-sync state, preventing misuse of the campaign link.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

imagine_get_adventure_pageGet an adventure pageA
Read-onlyIdempotent
Inspect

Fetch one adventure page by id with its full markdown body, tags, and parent reference. By default the gateway dereferences bracketed tag-* and child-* shortcodes and inlines a compact <expansion> block right after each literal. (rule-* shortcodes are NOT expanded on adventure pages because adventures do not carry a curated rule / spell / item association list; they remain as literals.) Pass raw: true to skip expansion when round-tripping the body back through imagine_update_adventure_page. Cross-references in the response: parent (resolve via imagine_get_adventure_page), worldPageRefs (array of world-page ids, resolve via imagine_get_world_page), and vaultRefs (array of {vaultId, type, count} for rules / spells / items / characters; resolve via the matching vault_get_* tool by type). Pair with imagine_list_adventure_pages to locate the id first.

ParametersJSON Schema
NameRequiredDescriptionDefault
idYesMongo `_id` of the adventure page.
rawNoWhen true, return the page body verbatim with bracketed shortcodes left as literals. Default: shortcodes are dereferenced and a compact <expansion> block is inlined after each literal. Pass raw=true when round-tripping a body back through imagine_update_adventure_page.

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.8/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

The description discloses the default dereferencing behavior, the fact that rule-* shortcodes are NOT expanded and why, and the raw:true escape hatch. It also explains the shape of cross-references (parent, worldPageRefs, vaultRefs) and how to resolve them. This goes well beyond the annotations (readOnly, idempotent, non-destructive) and adds real behavioral context.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is dense but well-organized: it front-loads the core fetch behavior, then explains expansion behavior, then cross-reference resolution, then pairing with the list tool. Every sentence earns its place, though the cross-reference sentence is long and could be slightly more scannable.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the output schema exists and the annotations cover safety, the description covers everything an agent needs: what is returned, how expansion works, when to use raw, how to resolve cross-references, and how to find the id. No critical gap remains.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, so the schema already documents both parameters. The description adds value by explaining the default vs raw behavior and the round-tripping use case, which enriches the raw parameter's meaning beyond the schema's description. The id parameter is straightforward and needs no extra explanation.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the tool fetches one adventure page by id, and specifies the returned content (markdown body, tags, parent reference). It also distinguishes itself from sibling tools like imagine_get_adventure_pages (plural) and imagine_get_world_page by naming the resource type and the resolution targets.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description explicitly explains when to use raw:true (round-tripping through imagine_update_adventure_page) and when not to (default expansion). It also tells the agent to pair with imagine_list_adventure_pages to locate the id first, and gives resolution guidance for cross-references. This is strong usage guidance.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

imagine_get_adventure_pagesGet many adventure pages at onceA
Read-onlyIdempotent
Inspect

Batch read of adventure pages by id (up to 50 per call). Use this when you need to walk an act and read several scenes' bodies — one call instead of one tool invocation per page. Each returned page carries the same shape imagine_get_adventure_page produces (full markdown body, ancestors, prev/next sibling navigation, expanded shortcodes by default). The response is { pages: [...], missing: [...] }; ids the caller can't view, or that don't exist, land silently in missing rather than failing the whole batch.

ParametersJSON Schema
NameRequiredDescriptionDefault
idsYesMongo `_id` list of adventure pages to fetch. Returns each page's full body, ancestors, and prev/next-sibling navigation in one round trip. Cap: 50 ids per request. Pages the caller can't view are silently omitted into a separate `missing` list rather than failing the batch.
rawNoWhen true, return each page body verbatim with bracketed shortcodes left as literals. Default: shortcodes are dereferenced and a compact <expansion> block is inlined after each literal, same as imagine_get_adventure_page.

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.5/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already mark the tool read-only and idempotent; the description adds valuable behavior beyond that: silent omission into a `missing` array instead of failing the batch, the 50-id cap, and default shortcode expansion with a raw escape hatch. These details materially affect how an agent interprets results.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Four dense sentences cover operation+cap, use case, return shape, and failure semantics with no filler. The most decision-relevant facts are front-loaded, and every sentence earns its place.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Together with the rich schema and output schema, the description gives the agent everything needed to invoke the tool correctly: batch limits, per-page output shape, shortcode behavior, and the distinction between returned pages and missing ids. Nothing relevant is left unexplained.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The input schema already documents both parameters in detail: Mongo `_id` list, 50-id cap, silent missing behavior, and the raw toggle. The description adds the return-shape relationship to imagine_get_adventure_page, but that is contextual framing rather than new parameter-level semantics. With 100% schema coverage, baseline 3 is appropriate.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific operation and resource: 'Batch read of adventure pages by id.' The 50-per-call cap and the reference to imagine_get_adventure_page clearly distinguish this from the single-page sibling, so an agent can identify it at a glance.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explicitly recommends this tool when walking an act and reading several scenes' bodies, framing it as one call instead of one tool invocation per page. It doesn't explicitly spell out the reverse case ('use imagine_get_adventure_page for a single page'), but the use context and sibling relationship are clear enough.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

imagine_get_adventure_recapsGet the session recaps for an adventureA
Read-onlyIdempotent
Inspect

Fetch the play-session recaps written while running this adventure, grouped by linked play campaign. Each campaign entry carries the sessions tagged with this adventure (via the session's imagineAdventureId) in date order, and each session carries its player-recap pages (author + markdown body). Read-through to play: the caller must be a member (owner or accepted player) of a linked campaign to read its sessions — on a PRIVATE adventure this is the recaps-only path. Recap visibility follows play's page rules: public recaps plus the caller's own private ones. Campaigns with no tagged sessions are omitted. Returns { campaigns: [] } when the adventure has no linked campaigns or nothing is visible to the caller. This replaces the manual walk of play_list_campaign_sessions + play_list_pages per session.

ParametersJSON Schema
NameRequiredDescriptionDefault
idYesMongo `_id` of the adventure.

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.4/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Beyond the readOnly/idempotent/non-destructive annotations, the description discloses important behavioral details: caller must be a campaign member, visibility follows play page rules, campaigns without tagged sessions are omitted, and the empty result shape is `{ campaigns: [] }`. This is exactly the kind of access-control and filtering context annotations do not capture.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is dense but purposeful, covering purpose, data shape, access rules, empty behavior, and the manual alternative in roughly four sentences. It is front-loaded with the core action and grouping, though the middle data-shape sentence is somewhat detailed given that an output schema already exists.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a read-only fetch tool with one well-documented parameter and an output schema, the description is complete: it explains what is fetched, how results are grouped, who can access what, when campaigns are omitted, and what the empty response looks like. Nothing an agent needs to invoke it correctly is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The single parameter `id` is already fully documented in the schema as the Mongo `_id` of the adventure, so the schema description coverage is 100%. The description adds no new parameter-level detail, but it does reference 'this adventure' contextually; baseline 3 is appropriate when the schema carries the parameter meaning.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The first sentence states a specific verb ('Fetch'), a precise resource ('play-session recaps written while running this adventure'), and the grouping behavior ('grouped by linked play campaign'). It also explicitly distinguishes itself from the manual walk of play_list_campaign_sessions + play_list_pages, so an agent can separate it from siblings.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description gives clear context: it is the recaps-only path for private adventures, requires membership in a linked campaign, and is positioned as the replacement for a manual multi-tool walk. It does not explicitly state when-not to use it versus sibling listing tools, but the alternative is named and the access conditions make usage clear.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

imagine_get_worldGet an imagine worldA
Read-onlyIdempotent
Inspect

Fetch one world by id with its settings, membership, and any user-linked play campaigns. The campaign link is informational only and is not auto-synced. Caller must have at least 'view' access to the world.

ParametersJSON Schema
NameRequiredDescriptionDefault
idYesMongo `_id` of the world.

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.3/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint=true, idempotentHint=true, and destructiveHint=false, covering the safety profile. The description adds valuable behavioral context beyond that: the campaign link is informational only and not auto-synced, and the caller must have view access. These details help the agent understand the tool's side effects and authorization requirements, which annotations do not provide.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is three sentences with no waste. The first sentence states the primary purpose and return content, the second clarifies a critical caveat, and the third states a permission prerequisite. It is front-loaded and every sentence earns its place.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the tool has an output schema (indicated) and only one parameter, the description is complete for correct invocation. It covers what the tool returns, the caveat about campaign links, and the required access level. No essential behavioral or usage information is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100% for the single parameter 'id', which is described as 'Mongo _id of the world'. The description does not add additional semantics beyond restating that it fetches by id; it does not provide format examples or extra constraints. Since the schema fully documents the parameter, a baseline score of 3 is appropriate.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the verb 'Fetch', the resource 'world', the identifier 'by id', and enumerates the specific data returned (settings, membership, user-linked play campaigns). It differentiates from sibling tools like imagine_get_world_page or imagine_list_my_worlds by specifying the exact scope and fields, so an agent can distinguish it without opening other schemas.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description provides a clear context: it is for fetching a single world by id with specific details, and it explicitly states the permission requirement ('Caller must have at least view access'). However, it does not explicitly mention when not to use it or name alternatives (e.g., imagine_list_my_worlds for listing), so it lacks explicit exclusions but still gives clear usage context.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

imagine_get_world_pageGet a world pageA
Read-onlyIdempotent
Inspect

Fetch one world page by id with its full markdown body, tags, and parent reference. By default the gateway dereferences bracketed shortcodes (tag-, child-, rule-*) and inlines a compact <expansion> block right after each literal so the LLM has the resolved content alongside what the author wrote. The original literal is preserved. Pass raw: true to skip expansion (useful when round-tripping the body back through imagine_update_world_page). Cross-references in the response: parent (another world page, resolve via imagine_get_world_page) and vaultCharacterId (vault character, resolve via vault_get_character). Pair with imagine_list_world_pages or imagine_search_world_pages to locate the id first.

ParametersJSON Schema
NameRequiredDescriptionDefault
idYesMongo `_id` of the world page.
rawNoWhen true, return the page body verbatim with bracketed shortcodes left as literals. Default: shortcodes are dereferenced and a compact <expansion> block is inlined after each literal so the LLM has the same content the human sees rendered. Pass raw=true if you're round-tripping a body back to imagine via imagine_update_world_page.

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.4/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Beyond annotations (readOnlyHint=true, idempotentHint=true), the description discloses the default expansion behavior (dereferencing shortcodes and inlining <expansion> blocks) and the preservation of the original literal. It also clarifies the effect of raw:true, providing substantial behavioral detail that the annotations do not cover.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is dense but each sentence serves a purpose: it starts with the core operation, then explains the default expansion, the raw override, cross-reference resolution, and how to locate the id. It is longer than strictly necessary but well-structured and front-loaded with the main function.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the output schema exists, the description appropriately omits return format details, but it adds valuable cross-reference resolution hints (parent and vaultCharacterId) and workflow guidance on locating the id. The tool is fully contextualized for an agent to call it correctly.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Both parameters are fully described in the input schema (100% coverage), so the baseline is 3. The description re-explains the raw parameter's behavior and adds a round-tripping use case, but this adds only marginal value beyond the schema, not enough to raise the score.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description opens with a specific verb and resource ('Fetch one world page by id') and enumerates the returned content (full markdown body, tags, parent reference). It differentiates itself from siblings by pairing with list/search tools to locate the id, implying this tool is for retrieval of a single known page.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It explicitly advises pairing with imagine_list_world_pages or imagine_search_world_pages to locate the id, and explains the raw:true option for round-tripping bodies back to imagine_update_world_page. This gives clear workflow context, though it does not describe when not to use the tool relative to other getters.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

imagine_list_adventure_pagesList pages in an adventureA
Read-onlyIdempotent
Inspect

List pages belonging to one adventure. Returns a tree-friendly summary per page (id, name, link, documentType, parent, menuOrder, locationKey, summary, image). Optional narrowing filters: parent (only direct children of that page — useful for an 'open this act' workflow), documentType (only pages of that type — useful for 'list every scene'). Both filters are combinable. Pair with imagine_get_adventure_page (single) or imagine_get_adventure_pages (batch) for full bodies.

ParametersJSON Schema
NameRequiredDescriptionDefault
idYesMongo `_id` of the adventure.
parentNoOptional. Mongo `_id` of a parent page. When set, only direct children of that page are returned (an act + its scenes pattern). Use imagine_list_adventure_pages without `parent` first to discover ids.
documentTypeNoOptional. Narrow to a single documentType (e.g. 'scene' to list every scene in the adventure).

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.7/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare read-only, idempotent, and non-destructive behavior, so the description only needs to add behavioral context. It adds that the result is tree-friendly, that parent filtering returns only direct children, and that both filters are combinable. These details go beyond the schema without contradicting the annotations.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Three compact sentences with no filler. The core action and return type are front-loaded, followed by filter semantics and sibling guidance. Every sentence earns its place.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

An output schema covers the return shape, annotations cover the safety profile, and all three parameters are fully described in both schema and description. Nothing an agent needs to call this tool correctly is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The schema already covers all three parameters at 100%, so the baseline is 3. The description adds meaning beyond the schema by clarifying direct-children semantics, showing realistic workflows for each filter, and stating that the filters are combinable.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description opens with a specific verb and resource: 'List pages belonging to one adventure,' and immediately clarifies it returns summaries rather than full page bodies. It also distinguishes itself from sibling tools like imagine_get_adventure_page and imagine_get_adventure_pages by naming them and describing the split.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It gives concrete when-to-use context for each optional filter: parent for an 'open this act' workflow, documentType for 'list every scene.' It also explicitly tells the agent to pair with imagine_get_adventure_page or imagine_get_adventure_pages when full bodies are needed, making alternatives and exclusions clear.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

imagine_list_adventure_partsList the parts of a series adventureA
Read-onlyIdempotent
Inspect

List the active parts (child adventures) of a series parent, ordered by menuOrder then name. Adventures can be grouped one level deep: an umbrella adventure (the campaign arc) with full adventures as its parts. Returns slim catalog-card fields per part (id, name, summary, image, ruleset, level, status, stock, link, version, parent, menuOrder). Parts the caller can't view are silently omitted. Returns an empty list for adventures that aren't a series parent. To make an adventure a part, set parent via imagine_update_adventure.

ParametersJSON Schema
NameRequiredDescriptionDefault
idYesMongo `_id` of the adventure.

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.7/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnly, idempotent, and non-destructive, so the description adds valuable behavioral context: only active parts are listed, ordering by menuOrder then name, one-level grouping, silent omission of unviewable parts, and empty-list behavior for non-parents. No contradiction with annotations.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is front-loaded with the core action and ordering, then adds behavioral edge cases and return fields without waste. Every sentence earns its place, and the field list is useful because it tells the agent exactly what shape to expect.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a read-only, single-parameter list tool with an output schema, the description covers all necessary behavior: ordering, active filter, permission-related omission, non-parent result, and how to create parts. Nothing material is missing for correct invocation.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The schema already documents the single id parameter with 100% coverage, so the baseline is 3. The description adds meaning by clarifying that the id must be a series parent, which is needed to interpret the empty-list case. This contextual enrichment goes slightly beyond the schema.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

Description states a precise verb and resource: list active child adventures (parts) of a series parent, with explicit ordering. This distinguishes it from sibling list tools like imagine_list_adventure_pages and imagine_list_my_adventures, so an agent can select it without guessing.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description clearly implies the tool is for series-parent adventures and explicitly covers the non-parent case (empty list), plus how to make an adventure a part. It does not name alternative tools, but the context is unambiguous enough for correct selection.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

imagine_list_my_adventuresList my adventuresA
Read-onlyIdempotent
Inspect

List the adventures the calling user owns or has access to. Returns slim catalog-card fields per adventure (id, name, summary, image, ruleset, level, status, stock, link, version, createdAt, updatedAt, parent, menuOrder). A non-null parent marks the adventure as one part of a series — see imagine_list_adventure_parts. To read a specific adventure's full body and configuration, call imagine_get_adventure with the id.

ParametersJSON Schema
NameRequiredDescriptionDefault

No parameters

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.7/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already establish readOnlyHint, idempotentHint, and destructiveHint, so the safety profile is covered. The description adds meaningful context beyond annotations by explaining the slim catalog-card scope, the series semantics of `parent`, and the relationship to detail-fetching tools.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Three sentences, each earning its place: the first states the core action and scope, the second lists the return fields, and the third handles related-tool routing. It is front-loaded and contains no filler.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With an existing output schema, comprehensive annotations, and no parameters, the description covers everything an agent needs to decide to call this tool and interpret the series-parent concept. Pagination and ordering are not mentioned, but nothing in the context signals they are essential for this simple list operation.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The tool has zero parameters and schema coverage is 100%, so there is no parameter documentation gap for the description to fill. The baseline of 4 applies because no semantic burden is placed on the description.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description opens with a specific verb and resource: 'List the adventures the calling user owns or has access to.' It clearly differentiates this tool from the related imagine_list_adventure_parts and imagine_get_adventure by stating what this tool returns versus what those tools are for.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explicit guidance is provided for related operations: when an adventure has a non-null `parent`, the reader is directed to imagine_list_adventure_parts, and when full body/config is needed, imagine_get_adventure is named. This gives an agent actionable routing without ambiguity.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

imagine_list_my_worldsList my imagine worldsA
Read-onlyIdempotent
Inspect

List the worlds the calling user owns or has access to via membership. Returns slim catalog-card fields per world (id, name, summary, image, link, createdAt, updatedAt). To read a specific world's full body and configuration, call imagine_get_world with the id.

ParametersJSON Schema
NameRequiredDescriptionDefault

No parameters

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.7/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already cover readOnlyHint, idempotentHint, and destructiveHint. The description adds value by specifying the return fields ('id, name, summary, image, link, createdAt, updatedAt') and the slim catalog-card nature, giving the agent a concrete expectation of output shape beyond what annotations provide. It doesn't contradict annotations.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two sentences, each earning its place. The first sentence states purpose and scope; the second lists return fields and points to the sibling tool. Fully front-loaded, no filler or redundancy.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a no-parameter list operation with an output schema already present, the description covers the essential context: scope of access, return field summary, and the escape hatch to get full details. An agent can call it correctly without further info. The description is thorough given the tool's simplicity.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The tool has zero parameters, so the description has no parameter details to add. Per baseline, a 0-param tool gets a 4. The description correctly avoids inventing parameter notes and focuses on behavior.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states a specific verb ('List') and resource ('worlds'), and clearly scopes it to 'owns or has access to via membership.' It also distinguishes itself from imagine_get_world, which reads a specific world's full body, so an agent knows this is a catalog listing operation.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description explicitly tells the agent when to use this over an alternative: 'To read a specific world's full body and configuration, call imagine_get_world with the id.' This is a clear routing statement. It also implicitly communicates the use case of listing all accessible worlds without needing parameters.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

imagine_list_world_pagesList pages in a worldA
Read-onlyIdempotent
Inspect

List all pages belonging to one world. Returns a tree-friendly summary (id, name, link, parentId, tags). Pair with imagine_get_world_page to fetch full content.

ParametersJSON Schema
NameRequiredDescriptionDefault
worldIdYesMongo `_id` of the world.

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.3/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint, idempotentHint, and non-destructive behavior. The description adds value beyond them by disclosing the return payload shape (id, name, link, parentId, tags) and that the result is a hierarchy-friendly summary rather than full content.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two sentences deliver purpose, return shape, and a companion-tool pointer with no filler. The core scope is front-loaded, making the definition easy to parse quickly.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a simple read-only list operation with one well-documented parameter, an output schema, and rich safety annotations, the description covers what an agent needs: scope, return type, and how to fetch full content. Nothing critical is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage for the single required parameter is 100%, with worldId described as a Mongo _id. The description only reinforces 'one world' without adding new parameter syntax, format, or edge-case details, so baseline 3 applies.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states a specific verb ('List') and resource ('all pages belonging to one world'), and identifies the return format as a tree-friendly summary, which distinguishes it from content-fetching siblings like imagine_get_world_page and tag-filtered variants. This is unambiguous and immediately actionable.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description provides clear workflow guidance by pairing this tool with imagine_get_world_page for full content, implying this tool is for summaries and navigation. It does not explicitly contrast with imagine_list_world_pages_by_tags or imagine_search_world_pages, so it misses full exclusionary guidance.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

imagine_list_world_pages_by_tagsList world pages by tagsA
Read-onlyIdempotent
Inspect

Filter pages within a world by one or more tags. The page's documentType is concatenated into the same keyword set imagine searches, so a tag query of 'character' also matches every page with documentType=character. Use mode='and' to require every tag; mode='or' (default) returns pages matching any tag. Common patterns: all NPCs (tag='npc'), all locations (tag='location'), every character-type page (tag='character').

ParametersJSON Schema
NameRequiredDescriptionDefault
modeNoTag-matching mode. 'or' (default) returns pages matching any tag; 'and' requires every tag.
tagsYesComma-separated list of tags (e.g. 'npc,villain' or just 'location').
worldIdYesWorld id.

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.7/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already mark the operation as read-only, idempotent, and non-destructive, and the description adds valuable hidden behavior: documentType is folded into the same keyword set, so a tag like 'character' also matches documentType=character. It also discloses the default mode ('or'), which is genuinely useful and not obvious from the schema alone.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is compact and front-loaded with the core action, then adds only high-value details about documentType, mode behavior, and common patterns. Every sentence earns its place without redundancy.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the output schema exists, annotations cover safety, and all parameters are documented in the schema, the description provides the remaining behavioral context an agent needs: how tags interact with documentType, the default/mode choices, and typical use cases. Nothing critical is missing for correct invocation.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, so the baseline is 3, but the description goes beyond the schema by explaining the unexpected documentType matching behavior and giving concrete tag examples. It clarifies the tags parameter more deeply than the schema's 'comma-separated list' description.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description opens with a specific verb and resource: 'Filter pages within a world by one or more tags.' It also clarifies what makes this tool distinct from plain listing/searching by explaining tag matching semantics, so an agent can identify it among siblings like imagine_list_world_pages and imagine_search_world_pages.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description gives concrete usage patterns ('all NPCs', 'all locations', 'every character-type page') and explains when to use mode 'and' vs 'or'. It does not explicitly name the sibling alternatives or say when not to use them, but the examples make the intended use clear.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

imagine_replace_in_adventure_pageReplace text inside one adventure pageA
Idempotent
Inspect

Surgical find-and-replace inside one adventure page's content. Every byte outside the matched ranges is preserved exactly, so this is the safe primitive for terminology passes (e.g. renaming a monster across a page) where imagine_update_adventure_page's whole-body replace would risk dropping formatting whitespace the LLM can't see in JSON. find matches literally (no regex). All occurrences are replaced in a single pass. Optional expectedOccurrences is a staleness guard — when set, a count mismatch returns 409 with no save instead of silently doing a partial edit. Returns { adventurePage, occurrences }.

ParametersJSON Schema
NameRequiredDescriptionDefault
idYesMongo `_id` of the adventure page.
findYesLiteral substring to replace inside the page's `content`. Match is literal (no regex); metacharacters are treated as ordinary characters.
replaceYesSubstring to put in place of every occurrence of `find`. May be empty to delete the matched text.
expectedOccurrencesNoOptional staleness guard. When set, the live page MUST contain exactly this many occurrences of `find` or the call fails with 409 and no save lands. Pre-count by fetching the page first if you want this protection.

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.7/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Beyond annotations (readOnlyHint=false, destructiveHint=false, idempotentHint=true), the description discloses key behaviors: byte-level preservation outside matches, single-pass replacement of all occurrences, the staleness guard returning 409 without saving on count mismatch, and the literal match semantics. This adds substantial behavioral context the annotations do not provide.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two sentences with no fluff. The first sentence front-loads the core purpose and key differentiator, the second covers matching, guard, and return. Every phrase earns its place, and the structure is easily scannable.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

The description covers the essential operational context: the safe usage, the alternative to avoid, the literal matching, the option for a staleness guard with its 409 behavior, and the return format. It even tells the agent to pre-count occurrences if protection is desired. With an output schema available, nothing material is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, so the schema already fully documents each parameter, including the literal match behavior and the staleness guard. The description adds context like 'single pass' and return value, but these are already implied by schema descriptions and output schema. It provides no new parameter-specific semantics beyond reinforcing the schema.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states a specific verb and resource: 'Replace text inside one adventure page's content'. It distinguishes itself from the sibling imagine_update_adventure_page by emphasizing 'surgical find-and-replace' that preserves every byte outside matched ranges, making its unique intent explicit.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Provides explicit usage context: it is the 'safe primitive for terminology passes' and directly contrasts with imagine_update_adventure_page, which 'would risk dropping formatting whitespace the LLM can't see in JSON.' This clearly tells an agent when to pick this tool over the alternative.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

imagine_search_world_pagesSearch world pages by textA
Read-onlyIdempotent
Inspect

Text search over page titles and raw markdown bodies within one world. Returns ranked summary results. Bracketed shortcodes (e.g. [[tag-card:goblin]]) match as literal text, not by the resolved content of the referenced entity, so this tool can miss content the human sees rendered. For category lookups (NPCs, locations, monsters), prefer imagine_list_world_pages_by_tags with the tag or documentType value.

ParametersJSON Schema
NameRequiredDescriptionDefault
queryYesSearch query text. Required.
worldIdYesMongo `_id` of the world to search within.

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.5/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint=true, idempotentHint=true, and destructiveHint=false, so the safety profile is covered. The description adds substantial behavioral context beyond annotations: the search scope (titles + raw markdown), the ranked-summary return shape, and critically the shortcode limitation where literal-text matching can miss rendered content. It stops short of pagination or result-limit behavior, but the output schema covers return structure.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Four sentences, each earning its place: purpose, return shape, the key gotcha, and the routing alternative. Information is front-loaded (purpose first) with the caveat and sibling guidance after. No filler, no repetition of schema or annotation content.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a two-parameter read-only search tool, the definition is complete: annotations cover safety, the output schema covers return values, the description covers scope, the known failure mode, and the correct sibling alternative. An agent has everything needed to decide when to call this tool and what to expect from it.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%: query and worldId each have meaningful descriptions in the schema. The description only marginally augments this by clarifying that the query runs against titles and raw markdown 'within one world,' reinforcing worldId's scoping role. Baseline 3 is appropriate since the schema carries the parameter documentation burden.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource: 'Text search over page titles and raw markdown bodies within one world.' It also explicitly distinguishes itself from the sibling tool imagine_list_world_pages_by_tags by scoping this tool to raw text search and the sibling to category/tag lookups. The title and description align cleanly with no ambiguity.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Provides explicit routing guidance: 'For category lookups (NPCs, locations, monsters), prefer imagine_list_world_pages_by_tags with the tag or documentType value.' It also flags when results may be incomplete (shortcodes matching literally), so an agent can warn the user or switch strategies. This is rare, explicit when-not-to-use guidance naming the exact alternative.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

imagine_update_adventureUpdate an adventureA
Idempotent
Inspect

PUT updates to one adventure by id. Only supplied fields are sent. Caller must have 'edit' on the adventure. Series grouping: set parent to group this adventure as one part of an umbrella adventure (depth-1 only — see the field description for the validation rules and the append-to-end ordering default); pass parent: null to ungroup. Linked play campaigns list the adventure under its current name, so a rename shows on them immediately. REQUIRES baseUpdatedAt: copy updatedAt from a fresh imagine_get_adventure read; a stale or fabricated value is rejected with OUT_OF_SYNC and nothing is written.

ParametersJSON Schema
NameRequiredDescriptionDefault
idYesAdventure id.
linkNoURL-safe slug. Lowercase letters, numbers, and hyphens. Imagine auto-suggests at create time when omitted.
nameNoAdventure name.
imageNoHeader image URL.
levelNoRecommended character level range. Each side optional; null means unset.
worldNoOptional World _id this adventure belongs to.
activeNo
parentNoSeries grouping: `_id` of the umbrella adventure this adventure is one part of. Depth is capped at one level — the parent cannot itself be a part, and an adventure that has parts cannot become a part (400 either way). The parent must be active and viewable by the caller (owner / contributor / public / stock), else 404. Pass null (or '') to clear. Setting a NEW parent without `menuOrder` appends the adventure to the end of the series.
publicNo
statusNo
rulesetNoRuleset code, from list_rulesets. Required at create.
summaryNoShort summary; capped at 150 characters by imagine.
versionNo
keywordsNoComma-separated keyword string used by adventure-wide tag/search.
barImagesNoGM-curated reference images displayed in a fixed bar across the adventure (maps, handouts, NPC portraits).
menuOrderNoSort position among sibling parts of the same series parent. Send alone to reorder an existing part; omit when setting `parent` so the server appends to the end.
partySizeNoRecommended party size range.
publisherNo
companionsNo
descriptionNoFull adventure description. Markdown supported.
baseUpdatedAtYesREQUIRED proof that you are working from the latest version: copy the `updatedAt` value verbatim from a FRESH read of this exact record (use the matching get tool first). Values from memory, from an earlier conversation, or guessed timestamps are rejected with OUT_OF_SYNC and nothing is written. After a successful update, the response carries the new `updatedAt` — use that for any follow-up write.
imageCarouselNo
estimatedHoursNo
contentWarningsNo

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.4/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint=false, idempotentHint=true, and destructiveHint=false, but the description adds substantial behavior beyond them: partial-update semantics, the 'edit' permission requirement, optimistic-concurrency via baseUpdatedAt with OUT_OF_SYNC and 'nothing is written' on failure, and rename propagation to linked campaigns. This is exactly the context an agent cannot get from the annotations.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loaded with the core verb+resource, then permission, then the two highest-risk behaviors (series grouping, baseUpdatedAt). Dense but every sentence carries operational weight; only the parent clause is slightly redundant with the field description it points to.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a 24-param mutation tool with an output schema and rich annotations, the description covers the contract-completing details an agent needs: partial update, auth, concurrency guard, and side effects on linked campaigns. Return values are covered by the output schema, so nothing essential is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

With 24 parameters and only 63% schema description coverage, the schema does most of the heavy lifting. The description adds real value for the tricky parameters (baseUpdatedAt workflow, parent grouping/ungrouping, menuOrder append default) but explicitly defers to the field description for parent validation and does not address the remaining undocumented fields. Baseline 3 is appropriate.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource ('PUT updates to one adventure by id') and is clearly distinguishable from siblings like imagine_update_adventure_page and imagine_create_adventure. The scope of a partial update ('Only supplied fields are sent') is stated up front, so an agent knows exactly what this tool mutates.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Gives clear prerequisites and routing: caller needs 'edit', and it explicitly directs the agent to a fresh imagine_get_adventure read before calling, with the OUT_OF_SYNC failure described. It does not spell out when to prefer a sibling like imagine_update_adventure_page, but for the common case the when-to-use is unambiguous.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

imagine_update_adventure_pageUpdate an adventure pageA
Idempotent
Inspect

PUT updates to one adventure page by id. Only supplied fields are sent; every field on the AdventurePage shape (name, content, summary, image, documentType, tags, parentId, link, menuOrder, aliases, details, worldPageRefs, vaultRefs, treasureRefs, scene-shape goal/duration, location-shape locationKey/map/mapPin) can be updated through this tool. Read-aloud / moving-on / tactics are NOT fields — author them inline in content as [[read-aloud]] / [[moving-on]] / [[tactics]] callout blocks. Caller must have 'edit'. WARNING about content: imagine REPLACES the body with whatever you send. To fix wording inside an existing body without losing formatting whitespace, prefer imagine_replace_in_adventure_page (surgical). To append, fetch the page first with imagine_get_adventure_page (raw=true), concatenate, and send the combined body back. REQUIRES baseUpdatedAt: copy updatedAt from a fresh imagine_get_adventure_page read of this page; a stale or fabricated value is rejected with OUT_OF_SYNC and nothing is written — writing from memory of an earlier read is not possible.

ParametersJSON Schema
NameRequiredDescriptionDefault
idYesAdventure page id.
mapNoLocation shape: Mongo `_id` of the Map this location belongs to. Pass null to clear.
goalNo
linkNoURL-safe slug. Lowercase letters, numbers, hyphens, slashes.
nameNoPage name.
tagsNoTag list. Imagine stores as a comma-separated `keywords` string.
imageNo
activeNo
mapPinNo
aliasesNo
contentNoPage body in markdown. Imagine renders this verbatim. WARNING: REPLACED wholesale on update; prefer imagine_replace_in_adventure_page for surgical edits.
detailsNoLabel/value list of arbitrary metadata pairs.
summaryNoShort page summary. Max 150 characters (matches the AdventurePage Mongoose schema's maxlength). Sibling Adventure and WorldPage summaries share the same cap; legacy World summaries cap at 255 (cross-app convention).
durationNo
parentIdNoMongo `_id` of the parent page (for tree structure).
templateNoTemplate id when authored from a template.
menuOrderNo
vaultRefsNoParticipants on the page. Each entry `{ vaultId?, type?, count?, name? }`.
locationKeyNo
documentTypeNoStructural type. Drives shape-specific fields.
treasureRefsNoTreasure entries. Same shape as `vaultRefs`.
baseUpdatedAtYesREQUIRED proof that you are working from the latest version: copy the `updatedAt` value verbatim from a FRESH read of this exact record (use the matching get tool first). Values from memory, from an earlier conversation, or guessed timestamps are rejected with OUT_OF_SYNC and nothing is written. After a successful update, the response carries the new `updatedAt` — use that for any follow-up write.
outboundLinksNoAdventurePage ids this page links to. Imagine recomputes this on save when missing; explicit values override.
relationshipsNoSibling AdventurePage ids the page relates to.
worldPageRefsNoMongo `_id` list of referenced world pages.

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.8/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already signal this is a write operation, but the description adds substantial behavioral detail: only supplied fields are sent, content is replaced wholesale, stale baseUpdatedAt values are rejected with OUT_OF_SYNC and nothing is written, and successful updates return a new updatedAt. It also discloses that read-aloud/moving-on/tactics are not fields but must be authored inline as callout blocks, which is valuable beyond the schema and annotations.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is long but information-dense, with the core verb, resource, and warnings front-loaded before alternatives and prerequisites. Every major sentence earns its place, though the long field enumeration and repeated warning about content could arguably be tightened without losing value.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a 25-parameter write tool with concurrency requirements and several nearby siblings, this description is unusually complete: it covers update semantics, the wholesale-content hazard, the required optimistic-locking workflow, the permission requirement, and the correct alternative for surgical edits. An output schema exists, so the absence of return-value detail is acceptable.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 68%, so the description does not need to fully re-document parameters, but it adds important meaning beyond the schema: the warning that content is replaced wholesale, the detailed required meaning of baseUpdatedAt, and the clarification that read-aloud/moving-on/tactics are not fields. It does not deeply explain the handful of parameters lacking schema descriptions, but it compensates reasonably for the main risk areas in an update tool.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description opens with a specific verb and resource ('PUT updates to one adventure page by id') and goes on to enumerate the full set of updateable fields, which clearly differentiates it from sibling get/create/replace tools. It also names the sibling surgical alternative, so an agent can distinguish this tool from imagine_replace_in_adventure_page without inspecting schemas.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description explicitly states when to use this tool versus alternatives: prefer imagine_replace_in_adventure_page for surgical content edits, and fetch via imagine_get_adventure_page with raw=true when appending. It also states the required permission ('Caller must have edit') and the mandatory fresh-read workflow for baseUpdatedAt, giving unambiguous selection and invocation guidance.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

imagine_update_worldUpdate an imagine worldA
Idempotent
Inspect

PUT updates to one world by id. Caller must have 'edit' access. Only supplied fields are sent; imagine merges them onto the existing document. REQUIRES baseUpdatedAt: copy updatedAt from a fresh imagine_get_world read; a stale or fabricated value is rejected with OUT_OF_SYNC and nothing is written.

ParametersJSON Schema
NameRequiredDescriptionDefault
idYesMongo `_id` of the world.
linkNoURL-safe slug for the world (lowercase letters, digits, hyphens). Imagine auto-suggests at create time when omitted.
menuNoSite menu entries — label + optional link/pageId/order.
nameNoWorld name.
imageNo
activeNo
publicNoWhether the world is public. Only Premium, VIP, and admin accounts can change whether a world is public; the server refuses the change from anyone else. A new world is public unless set otherwise.
faviconNo
summaryNoShort summary; capped at 255 characters. Cross-app convention (per dev-sites/AGENTS.md); the Mongoose World schema still accepts up to 500 as a legacy inconsistency being migrated, but new authoring should keep summaries under 255.
calendarNoOptional calendar definition (months[] + eras[]).
keywordsNo
showInviteNo
descriptionNoFull world description. Markdown supported.
customDomainNoOptional custom domain pointing at the world's public site.
baseUpdatedAtYesREQUIRED proof that you are working from the latest version: copy the `updatedAt` value verbatim from a FRESH read of this exact record (use the matching get tool first). Values from memory, from an earlier conversation, or guessed timestamps are rejected with OUT_OF_SYNC and nothing is written. After a successful update, the response carries the new `updatedAt` — use that for any follow-up write.
imageCarouselNo
isExampleWorldNo

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.7/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Beyond the annotations, the description discloses optimistic concurrency (stale baseUpdatedAt causes OUT_OF_SYNC and no write), the partial-merge behavior, the permission requirement, and the need to reuse the returned updatedAt for follow-up writes. This adds substantial behavioral context and does not contradict any annotation.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Three tight sentences front-load the method and resource, then state the access requirement, the merge behavior, and the mandatory concurrency field. Every sentence earns its place, and the uppercase REQUIRES makes the critical constraint unmissable.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a 17-parameter update with nested objects, the description covers the essential call protocol: fresh read, merge semantics, permission, stale rejection, and post-write updatedAt handling. The remaining field-level details live in the schema and output schema, so nothing an agent needs to call this correctly is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The description adds critical parameter-level meaning by explaining that only supplied fields are sent and merged onto the existing document, preventing an agent from assuming omitted fields get reset. It also reinforces the baseUpdatedAt freshness rule, though the schema itself already documents baseUpdatedAt in detail.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description opens with 'PUT updates to one world by id,' naming the HTTP method, action, and exact resource scope in one phrase. This clearly distinguishes it from sibling update tools like imagine_update_adventure and imagine_update_world_page, which target different resources.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description explicitly states the edit-access prerequisite, the required fresh imagine_get_world read, and the merge semantics for partial updates, giving an agent clear call-flow context. It does not explicitly name alternatives or state when not to use this tool, but for an update-by-id operation the guidance is strong enough.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

imagine_update_world_pageUpdate a world pageA
Idempotent
Inspect

PUT updates to one world page by id. Only supplied fields are sent. Caller must have 'edit' on the world page. Imagine REPLACES the content body with whatever you send. To append, fetch the page first with imagine_get_world_page, concatenate, and send the combined body back. REQUIRES baseUpdatedAt: copy updatedAt from a fresh imagine_get_world_page read of this page; a stale or fabricated value is rejected with OUT_OF_SYNC and nothing is written — writing from memory of an earlier read is not possible. Set visibility: 'gm' to make a page GM-only (owner/contributors only; hidden from and 404 for everyone else), 'masked' to keep it participating in lists/backlinks under maskName with the real identity hidden, or 'public' to reveal it. Hidden pages are stripped from the world menu.

ParametersJSON Schema
NameRequiredDescriptionDefault
idYesWorld page id.
linkNoURL-safe slug. Lowercase letters, numbers, hyphens, slashes.
nameNoPage name.
tagsNoTag list. Stored as a comma-separated `keywords` string on the wire.
imageNo
activeNo
aliasesNo
contentNoPage body in markdown. Imagine renders this verbatim. REPLACED wholesale on update.
detailsNo
gmNotesNoGM-only notes attached to the page.
rulesetNo
summaryNoShort page summary; capped at 150 characters by imagine.
maskNameNoWhat non-contributors see instead of the page's name while visibility is 'masked'. Empty renders as 'Redacted'.
parentIdNoMongo `_id` of the parent world page (tree structure).
templateNo
eventDateNoOptional in-world event date for chronology-shape pages.
menuLabelNo
menuOrderNo
showInMenuNo
visibilityNoPage visibility. 'gm' pages exist only for the world's owner and contributors — every other viewer gets a 404 and the page is absent from lists, search, backlinks, and breadcrumbs. 'masked' pages participate in lists, tags, backlinks, and breadcrumbs but present maskName/maskSummary and an id-based URL to non-contributors; the real name, link, content, and aliases stay hidden until the page is flipped to public. Hidden pages are barred from the world menu. Default: 'public'.
maskSummaryNoOptional teaser non-contributors see on the masked page; the real summary and content stay hidden. Max 255 characters.
documentTypeNo
isWorldChildNo
baseUpdatedAtYesREQUIRED proof that you are working from the latest version: copy the `updatedAt` value verbatim from a FRESH read of this exact record (use the matching get tool first). Values from memory, from an earlier conversation, or guessed timestamps are rejected with OUT_OF_SYNC and nothing is written. After a successful update, the response carries the new `updatedAt` — use that for any follow-up write.
outboundLinksNo
relationshipsNo
showBreadcrumbsNo
vaultCharacterIdNoBind this page to a vault character (for character-shape world pages).
playCampaignCharactersNo

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.5/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Goes beyond annotations by disclosing that content is replaced wholesale, that only supplied fields are sent, that OUT_OF_SYNC aborts the write, and how visibility levels behave (404 for GM-only, maskName for masked). These are behavioral traits annotations do not convey (idempotentHint true doesn't capture replacement semantics). No contradiction.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Packed with warnings but front-loaded with the core action. Some redundancy with schema descriptions (visibility, baseUpdatedAt) makes it slightly longer than necessary, but every sentence serves a purpose.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Handles the high-stakes behaviors: replacement, optimistic concurrency, and visibility. The existence of an output schema covers return-value details. However, with 29 parameters and nested structures, it doesn't clarify formats for many fields (e.g., how outboundLinks or playCampaignCharacters are structured) – though the schema's types partially cover that.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema covers the essential traps (baseUpdatedAt, visibility, content replacement) in its own descriptions, and the tool description largely repeats those rather than adding new per-field meaning. It adds the cross-cutting 'Only supplied fields are sent' note commonsensically but does not compensate for the 52% of parameters that lack schema descriptions (e.g., relationships, outboundLinks, menuOrder).

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States 'PUT updates to one world page by id' – a specific verb, resource, and scope that clearly distinguishes it from sibling update tools (imagine_update_world, imagine_update_adventure_page) and the create/delete world-page tools.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explicitly says to fetch first with imagine_get_world_page before append, lists the edit permission prerequisite, and warns that stale baseUpdatedAt is rejected with OUT_OF_SYNC. This gives the agent clear when-to and when-not-to guidance.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

list_my_submissionsList my bug reports and requestsA
Read-onlyIdempotent
Inspect

List the calling user's own submissions (bug reports and feature requests) with each one's status: new, reviewing, clarification (Embers is waiting on the user), planned, resolved, declined, or closed (read-only, 30 days after resolved or declined).

ParametersJSON Schema
NameRequiredDescriptionDefault

No parameters

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.5/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint=true, idempotentHint=true, and destructiveHint=false, so the safety profile is covered. The description adds valuable behavioral context by explaining the meaning of the 'clarification' status (Embers is waiting on the user) and the 'closed' status read-only behavior, which goes beyond the schema. It does not mention ordering, pagination, or rate limits, but these are not critical for a simple read-only list.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is a single sentence that is front-loaded with the primary action and scope, then efficiently packs the status list with useful clarifications. Every element earns its place, and there is no redundant wording.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the tool's low complexity (no parameters, simple listing operation) and the presence of an output schema (which the description need not explain), the description is complete. It specifies exactly what is returned (submissions with statuses) and adds value by explaining the meaning of two important statuses. An agent can invoke this tool correctly with no additional information.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The tool takes zero parameters, and the schema coverage is 100% (empty object). With no parameters to document, the description naturally does not add parameter-level detail. The baseline score of 4 for 0-parameter tools applies here.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the action ('List') and scope ('the calling user's own submissions'), specifies the resource type ('bug reports and feature requests'), and enumerates all possible statuses. This distinguishes it from sibling tools like get_submission (retrieves one submission) and create_submission (creates one).

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description clearly indicates this is for listing the caller's own submissions, which distinguishes it from any hypothetical tool that lists all submissions. However, it does not explicitly reference sibling tools like get_submission for single-item retrieval or mention when not to use it, leaving some inference to the agent.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

list_rulesetsList allowed rulesetsA
Read-onlyIdempotent
Inspect

Return the ruleset codes the calling user is permitted to use across the Embers ecosystem. Includes the always-public rulesets plus any restricted rulesets the user has been granted access to. Use this before populating any ruleset selector or before filtering vault/play/imagine results by ruleset.

ParametersJSON Schema
NameRequiredDescriptionDefault

No parameters

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.5/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already cover read-only, idempotent, and non-destructive behavior. The description adds value by explaining that it returns user-specific permitted codes and includes both public and restricted entries, which goes beyond the annotations. No contradiction with annotations.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two sentences with no wasted words. The action and scope are front-loaded, and the usage guidance is brief and clear.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

The tool is simple (no parameters, output schema exists), and the description fully covers what it returns and when to use it. Nothing missing for correct invocation.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

There are zero parameters, so the schema coverage is trivially 100%, and the baseline is 4. The description correctly omits parameter details because none exist.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the specific verb 'Return' and the resource 'ruleset codes the calling user is permitted to use'. It distinguishes itself by mentioning the inclusion of always-public and restricted rulesets, and its unique role among siblings (no other tool lists permitted rulesets).

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description explicitly says 'Use this before populating any ruleset selector or before filtering vault/play/imagine results by ruleset', giving clear guidance on when to invoke it. It does not mention when not to use it or alternatives, but given the unique purpose, this is sufficient.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

play_accept_friend_requestAccept a friend requestA
Idempotent
Inspect

Accept a pending friend request directed at the calling user. Pass friendId — the _id of the friend record on the calling user's friends list (from play_list_pending_friends), NOT the requester's user id.

ParametersJSON Schema
NameRequiredDescriptionDefault
friendIdYes`_id` of the friend record on the calling user's friends list. NOT the other user's id. Use play_list_pending_friends (for accept/decline) or play_list_my_friends (for remove) to obtain it.

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.1/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

The description makes clear this is an action on a pending friend request, which is consistent with the annotations (readOnlyHint=false, destructiveHint=false, idempotentHint=true). It does not add much behavioral context beyond what the annotations and verb already convey, such as what state changes occur or what happens on success.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two tightly written sentences with no filler. The action is stated first, and the parameter warning is front-loaded with the most important clarification about what friendId is not.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a single-parameter tool with 100% schema coverage, a clear description, an output schema, and annotations covering idempotency and destructiveness, nothing essential is missing. The description gives the agent enough to call the tool correctly.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so the schema already fully documents friendId. The description reinforces the critical distinction that friendId is the friend record's _id, not the requester's user id, but it does not add meaning beyond what the schema already states.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description names a specific verb and resource: accept a pending friend request directed at the calling user. It distinguishes itself from related friend-request siblings by emphasizing that the request must be pending and targeted at the caller, so an agent can tell it apart from send, decline, cancel, or remove.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description gives clear context for when to use this tool: there is a pending friend request directed at the calling user. It also routes the agent to play_list_pending_friends as the source for the required ID. It does not explicitly name alternatives like play_decline_friend_request, but the usage context is clear enough.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

play_add_campaign_characterAdd a character to a campaignAInspect

Attach a vault character to a play campaign so the character participates in play. Play places the attachment on the campaign leg matching the vault character's own ruleset — the campaign must have an active leg for that ruleset. Caller must have campaign 'contribute' permission. Use vault_search_characters to locate the character id first.

ParametersJSON Schema
NameRequiredDescriptionDefault
npcNotrue if this character is added as a DM-controlled NPC; false / omitted = player character.
campaignIdYesCampaign id.
characterIdYesVault character id to add. Required.

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.3/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

The description discloses a non-obvious behavior: the attachment is placed on the campaign leg matching the vault character's ruleset, not chosen by the caller. It also adds a permission requirement ('contribute') that annotations do not capture. Since the annotations are all false flags, this behavioral detail is especially valuable, though duplicate-attachment behavior is not addressed.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Three tight, purposeful sentences: action, behavioral constraint, then permission and workflow. Every sentence carries new information and the most important content is front-loaded.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given an output schema and a simple 3-parameter input, the description covers the prerequisite active leg, the ruleset-matching behavior, the permission requirement, and the pre-step for locating the character id. An agent has everything needed to invoke this tool correctly.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so the baseline is 3; campaignId, characterId, and npc are already documented in the schema. The description adds workflow context for characterId by referring to a 'vault character' and its ruleset, but it doesn't need to restate parameter definitions.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description opens with a specific verb-resource pair ('Attach a vault character to a play campaign') and states the purpose ('so the character participates in play'). It clearly differentiates this from read/list tools like play_list_campaign_characters and from vault_attach_companion by focusing on play campaign participation.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description gives clear context: the campaign must have an active leg matching the character's ruleset, and the caller needs 'contribute' permission. It also instructs the agent to use vault_search_characters first to locate the character id. It doesn't explicitly state when-not-to-use, but no natural alternative tool exists for this exact operation.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

play_add_campaign_itemAdd an item to a campaign's allowlistAInspect

Add a vault item to a campaign's allowlist. The item always lands on the leg matching the ITEM's own ruleset — the campaign must have a leg for that ruleset or play answers 400. The optional ruleset param never retargets; it only confirms the expected leg, and a mismatch answers 400. Caller must have 'contribute' on the campaign.

ParametersJSON Schema
NameRequiredDescriptionDefault
itemIdYesVault document id (`itemId`). Required.
rulesetNoOptional confirmation of the target leg's ruleset. The entity always lands on the leg matching its OWN ruleset — this param never retargets; when present, play verifies it matches that leg and answers 400 on a mismatch. Omit unless you want the placement double-checked.
campaignIdYesCampaign id.

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.7/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Goes well beyond the annotations (readOnly=false, destructive=false, idempotent=false) by disclosing two distinct 400 failure modes, the placement rule that the item lands on the leg matching its own ruleset, and the required 'contribute' permission. These are exactly the traits an agent cannot infer from the flags or schema.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Three sentences, front-loaded with the action, then the leg rule, then the permission. No filler, no restating of the title, and the 400 conditions are attached to the behaviour that causes them.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With an output schema present, return values need no explanation. Preconditions, permission requirement and the two error paths are all covered, which is everything needed to invoke this mutation correctly.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, so the baseline is 3; the description still earns a bump by hammering the counter-intuitive point that `ruleset` never retargets and only acts as a confirmation that errors on mismatch. It clarifies intent rather than adding new syntax.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

Specific verb + resource ('Add a vault item to a campaign's allowlist') that cleanly separates it from the many play_add_campaign_* siblings (spell, rule, character, leg). An agent knows exactly what is being added and to what container.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Gives the operative preconditions: the campaign must already have a leg for the item's ruleset, and the caller must hold 'contribute'. It does not, however, name when to prefer this over sibling allowlist tools or what to do instead when the leg is missing (e.g. call play_add_campaign_leg).

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

play_add_campaign_legAdd a ruleset leg to a campaignAInspect

Add a new active leg to a campaign for the given ruleset, letting the same campaign (same sessions, players, and history) also run under that ruleset. The new leg starts empty — no rules, items, spells, or characters; fill it with the add tools. One leg per ruleset: play answers 409 if a leg for this ruleset already exists. Caller must be the campaign owner or an accepted gamemaster; ordinary players get 403.

ParametersJSON Schema
NameRequiredDescriptionDefault
rulesetNoRuleset code for the new leg; list_rulesets returns the codes this account can use. Required. One leg per ruleset — play answers 409 if the campaign already has a leg for this ruleset, 400 for an unknown code, and 403 for a ruleset this account is not entitled to.
campaignIdYesCampaign id.

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.5/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Goes well beyond the annotations by disclosing that the new leg starts empty (no rules/items/spells/characters), that duplicate ruleset legs yield a 409, and that the caller must be the owner or an accepted gamemaster or receive a 403. These are exactly the preconditions and side effects an agent needs for a non-idempotent mutation.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loads the action, then the empty-leg behavior, then the constraint and auth in a compact, well-ordered three-sentence block with no wasted text.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With an output schema present, return values need no explanation; the description covers authorization, emptiness, and the duplicate-ruleset error path, leaving nothing an agent needs to call this correctly.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so the schema already documents both parameters including the 400/403/409 error conditions for the ruleset code. The description only restates 'for the given ruleset' and the 409, adding little beyond the schema; baseline 3 applies.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource ('Add a new active leg to a campaign for the given ruleset') and explains the concept of a 'leg' as the same campaign running under another ruleset. This clearly distinguishes it from the sibling add tools (play_add_campaign_rule/item/spell/character) which fill the leg rather than create it.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explains the scenario for the call and routes the agent onward ('fill it with the add tools'), and gives the selection constraint 'one leg per ruleset'. It does not name an explicit alternative tool, but there is no direct competing tool, so the context is clear.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

play_add_campaign_ruleAdd a rule to a campaign's allowlistAInspect

Add a vault rule to a campaign's allowlist. The rule always lands on the leg matching the RULE's own ruleset — the campaign must have a leg for that ruleset or play answers 400. The optional ruleset param never retargets; it only confirms the expected leg, and a mismatch answers 400 (e.g. "This rule is X, not Y"). Caller must have 'contribute' on the campaign.

ParametersJSON Schema
NameRequiredDescriptionDefault
ruleIdYesVault document id (`ruleId`). Required.
rulesetNoOptional confirmation of the target leg's ruleset. The entity always lands on the leg matching its OWN ruleset — this param never retargets; when present, play verifies it matches that leg and answers 400 on a mismatch. Omit unless you want the placement double-checked.
campaignIdYesCampaign id.

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.3/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare the write/safety profile (readOnly=false, destructive=false, idempotent=false), so the description only needs to add context — and it does: the leg-matching rule, the 400 failure mode, and the required 'contribute' permission. Non-obvious behavior around the ruleset param is disclosed well.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Four tight sentences, front-loaded with the action, then leg behavior, param semantics, and permission. Every sentence carries distinct information with no filler.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With an output schema present, return values needn't be described. The description covers placement behavior, error conditions, and authorization, leaving nothing an agent needs in order to call it correctly.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, so the baseline is 3. The description restates the ruleset confirmation semantics that the schema already documents in full; it adds emphasis but little new meaning beyond the structured field.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource ('Add a vault rule to a campaign's allowlist'), which is unmistakably distinct from siblings like play_remove_campaign_rule or play_add_campaign_item. An agent can identify the operation without opening the schema.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Gives clear preconditions: the campaign must have a leg matching the rule's own ruleset, and the caller needs 'contribute'. It stops short of naming an explicit alternative or exclusion, but the situational context is strong.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

play_add_campaign_spellAdd a spell to a campaign's allowlistAInspect

Add a vault spell to a campaign's allowlist. The spell always lands on the leg matching the SPELL's own ruleset — the campaign must have a leg for that ruleset or play answers 400. The optional ruleset param never retargets; it only confirms the expected leg, and a mismatch answers 400. Caller must have 'contribute' on the campaign.

ParametersJSON Schema
NameRequiredDescriptionDefault
rulesetNoOptional confirmation of the target leg's ruleset. The entity always lands on the leg matching its OWN ruleset — this param never retargets; when present, play verifies it matches that leg and answers 400 on a mismatch. Omit unless you want the placement double-checked.
spellIdYesVault document id (`spellId`). Required.
campaignIdYesCampaign id.

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.2/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Beyond the annotations (which only declare readOnly=false, destructive=false, idempotent=false, openWorld=true), the description adds the leg-placement rule, the two 400 failure conditions, and the required 'contribute' permission. It does not address what happens on a duplicate add (relevant given idempotentHint=false), leaving a modest gap.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Three sentences, each earning its place, with the core action front-loaded and the constraints on ruleset and permissions following in priority order. No filler.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With 100% schema coverage, an output schema present, and annotations covering the safety profile, the description supplies the remaining behavioral essentials (placement rule, error triggers, permission). Only the duplicate-add / non-idempotent behavior is left unstated.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so all three params are already documented. The description's explanation of the optional `ruleset` param as confirm-only largely restates the schema text rather than adding new syntax or format detail. Baseline 3 is appropriate.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource ('Add a vault spell to a campaign's allowlist'), which is clearly distinct from the sibling play_remove_campaign_spell and play_list_campaign_spells. An agent can identify the operation without consulting the schema.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Gives concrete operational conditions: the spell lands on the leg matching its own ruleset, the campaign must have that leg or play answers 400, and the caller needs 'contribute'. It does not explicitly contrast with siblings like play_add_campaign_item or state when-not to use it, so it falls short of a 5.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

play_cancel_friend_requestCancel a friend requestA
DestructiveIdempotent
Inspect

Cancel a friend request the calling user previously sent. Pass friendId — the _id of the friend record on the calling user's own friends list (the one the caller initiated).

ParametersJSON Schema
NameRequiredDescriptionDefault
friendIdYes`_id` of the friend record on the calling user's friends list. NOT the other user's id. Use play_list_pending_friends (for accept/decline) or play_list_my_friends (for remove) to obtain it.

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.5/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already mark the operation as destructive and idempotent. The description adds meaningful behavioral context beyond those hints: it can only cancel requests the calling user initiated, and it targets the friend record on the user's own friends list, not the other user's id. This helps the agent avoid common misuse.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two focused sentences with no filler. The action and the key disambiguation are front-loaded, and the parameter guidance is placed exactly where it is relevant.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a single-parameter, output-schema-bearing mutation tool with annotations covering destructiveness and idempotency, the description is complete. It identifies the target, the required parameter, how to source that parameter, and the boundary of what it can cancel.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, so the baseline is 3. The description adds value by emphasizing that friendId is the friend record on the caller's own friends list and specifically the one the caller initiated, and by directing the agent to the sibling list tools that produce this value. This goes slightly beyond the schema's own wording.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states a specific verb ('Cancel') and resource ('a friend request the calling user previously sent'), and clarifies scope by noting it must be a request the calling user initiated. This clearly distinguishes it from siblings like play_accept_friend_request, play_decline_friend_request, and play_remove_friend.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description indicates when the tool applies (only to requests the calling user previously sent) and the parameter description points to play_list_pending_friends and play_list_my_friends as sources for the required friendId. It does not explicitly state when NOT to use this tool versus decline or remove, but the caller-initiated qualifier largely disambiguates.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

play_check_recap_existsCheck if the user already wrote a recap for a sessionA
Read-onlyIdempotent
Inspect

Cheap boolean check — returns { exists: boolean } for whether the calling user has an active player-recap page attached to the given session. Use this to gate play_create_page so you don't write a duplicate recap.

ParametersJSON Schema
NameRequiredDescriptionDefault
sessionIdYesMongo `_id` of the session.

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.5/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint, idempotentHint, and destructiveHint, so the description is not burdened with those. It adds value by stating it's a 'cheap boolean check' and scoping to the 'calling user' and 'active player-recap page,' which are behavioral details beyond the schema. It does not mention error conditions, but given the simplicity and annotation coverage, this is acceptable.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two sentences with zero waste. The core purpose and return shape are front-loaded in the first sentence, and the usage guidance in the second. Every word earns its place.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a simple existence check with one well-documented parameter, annotations covering safety, and an output schema hinted in the description, nothing essential is missing. The description covers the return value, scope, and intended usage context.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100% for sessionId, so the schema fully documents the parameter. The description does not add any extra semantics beyond what the schema provides, thus the baseline score of 3 is appropriate.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states a specific verb (check) and resource (recap existence) with a precise return contract ({ exists: boolean }). It differentiates itself from siblings like play_create_page by focusing on the read-only existence check, leaving no ambiguity about its function.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explicitly instructs when to use it: 'Use this to gate play_create_page so you don't write a duplicate recap.' This names the alternative tool and the condition that selects this check, providing direct and unambiguous guidance.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

play_consume_pbem_emailsLink inbox emails to a moveAInspect

Mark inbox emails consumed and link them to the move they were collated into. Use after play_create_move / play_update_move when building a move from emails. Only 'new' items in the move's campaign are affected. GM-only.

ParametersJSON Schema
NameRequiredDescriptionDefault
moveIdYesThe move the items were collated into.
itemIdsYesInbox item ids that were collated into the move.

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.2/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already establish this is a mutation (readOnlyHint=false) and non-destructive (destructiveHint=false). The description adds valuable behavioral context beyond annotations: it marks emails as consumed, links them to a move, restricts effects to 'new' items, and notes GM-only access. No contradictions with annotations.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Three sentences with zero fluff: action, usage timing, and scope condition. The core function is front-loaded, and every sentence earns its place. The GM-only note is concise and necessary.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a simple 2-parameter tool with an output schema and annotations, the description covers when to use, what it does, and its scope. It could clarify what 'consumed' means for the inbox (e.g., removal vs. archiving) or define 'new', but these are minor given the output schema likely conveys return state.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so both parameters are already fully documented. The description adds a behavioral constraint ('Only new items... affected') that indirectly relates to itemIds, but it does not add parameter-specific meaning beyond schema. Baseline 3 is appropriate.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states a specific action ('Mark inbox emails consumed and link them to the move'), a clear resource and target, and the use context ('after play_create_move / play_update_move'). It distinguishes from sibling PBEM tools by specifying 'consumed' and 'collated into', which implies a state change tied to a move rather than simple dismissal or resolution.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description explicitly tells the agent when to use the tool: after play_create_move/play_update_move when building a move from emails. It also gives a scoping condition ('Only new items... affected'). It does not list alternatives or explicit when-not-to-use scenarios, but the context is clear enough for correct routing.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

play_create_campaignCreate a play campaignAInspect

Create a new campaign owned by the calling user. Required: name. ruleset becomes the campaign's first leg (campaigns hold ruleset-specific material in per-ruleset legs; add more with play_add_campaign_leg). Other fields (summary, description, settings) pass through to play, which validates the payload.

ParametersJSON Schema
NameRequiredDescriptionDefault
nameYesCampaign name. Required.
imageNoImage URL. Stored as a plain string.
activeNo
publicNoWhether non-members can see the campaign.
rulesetNoRuleset code; list_rulesets returns the codes this account can use. Becomes the campaign's first leg. Play enforces required and a known code on the backend (400) and answers 403 for a ruleset this account is not entitled to; the gateway lets it be omitted so the LLM gets a clean backend error if it forgets.
summaryNoShort campaign summary. Max 150 characters.
sessionsNo
descriptionNoFull campaign description. Markdown supported.
hideSectionsNo
xCardEnabledNo

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.3/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare this as a non-read-only, non-idempotent, non-destructive, open-world write. The description adds meaningful specifics beyond that: ownership semantics, that 'ruleset' is materialized as a leg, and that Play validates the payload (400 for missing/unknown ruleset, 403 for unentitled ruleset). It does not cover reversibility or rate limits, so it stops short of the top score.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Three tight sentences, front-loaded with the operation and the required field, then the leg/validation detail. Slightly dense in the middle clause about legs, but no filler.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a 10-parameter creation tool, it covers purpose, required field, the non-obvious leg mechanic, and backend failure modes, while an output schema exists so return values need no prose. Annotations carry the safety profile. Only unusual params like hideSections/xCardEnabled are left to the schema.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 60%, so the schema documents about half the parameters. The description compensates by explaining the pass-through contract for summary/description/settings and the leg behavior plus backend error codes for ruleset, adding real meaning beyond the schema text.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource ('Create a new campaign') plus scope ('owned by the calling user'), which cleanly separates it from play_update_campaign, play_delete_campaign, and the imagine_create_* siblings. An agent can identify the operation without opening the schema.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explains the setup context: required 'name', and that 'ruleset' becomes the campaign's first leg with more legs added via play_add_campaign_leg. It names the follow-up tool but does not state exclusions or when a different creation path (e.g. imagine_create_adventure) would be preferred.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

play_create_moveCreate a moveAInspect

Record a new play-by-email move on a campaign. Required: campaignId. Optional: name (defaults 'Move '), number (defaults next-in-sequence), date dd/mm/yy (defaults today), description, sessionId (chapter), parentId (child scene; excludes sessionId), playerIds (visibility restriction to listed campaign players). GM-only: caller must be the campaign owner or an accepted gamemaster.

ParametersJSON Schema
NameRequiredDescriptionDefault
dateNoMove date in `dd/mm/yy` format. Defaults to today on create. Play parses this server-side on both create and update.
nameNoMove name / title (e.g. 'Move 185', 'Interlude 12'). Defaults to 'Move <number>' when omitted on create.
numberNoGame label number. Non-unique (parallel scenes share one). Defaults to the campaign's high-water + 1 on create. Display position is `order`, not this.
parentIdNoParent move, making this a child scene (split party). Same campaign only, one level deep (a child cannot be a parent; a move with children cannot become a child). Children render on the parent's page, stay out of the feed and chapter lists, and cannot carry a sessionId. Pass null to detach back into the feed.
playerIdsNoVisibility restriction: user ids from the campaign's player roster. Empty/omitted = visible to every campaign participant. When set, the move is invisible to players not listed (dropped from lists, 404 on read); the GM always sees it. Pass [] on update to reopen the move to everyone.
sessionIdNoChapter session to group this move under. Must belong to the same campaign. Pass null to detach the move back to the unchaptered feed.
campaignIdYesCampaign the move belongs to. Required. Caller must be the campaign owner or an accepted gamemaster.
descriptionNoThe collated round: GM narration, player contributions, rolls. Markdown supported.

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.3/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

The annotations provide only false hints, so the description carries most of the behavioral disclosure burden. It does so well by revealing the GM-only requirement, defaulting behavior for name/number/date, and visibility restrictions via playerIds. It does not describe the response shape, but an output schema exists, and the description does not contradict any annotation.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is compact and well organized: a one-line purpose, then required vs. optional parameters, then the GM-only constraint. Every sentence earns its place, and the core action is front-loaded. There is no filler or redundancy.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For an 8-parameter creation tool, the description together with the fully covered schema and output schema gives an agent everything needed to call it correctly: required campaignId, default behaviors, key constraints, and authorization. Nothing essential is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, with detailed parameter explanations already present, so the baseline is 3. The description condenses important information such as 'parentId (child scene; excludes sessionId)' and 'playerIds (visibility restriction)', but it mostly mirrors the schema rather than adding new semantic meaning. It is useful for quick scanning but does not materially extend the schema.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states a specific verb and resource: 'Record a new play-by-email move on a campaign.' This clearly distinguishes it from sibling tools like play_create_session or play_create_page, and the PBEM qualifier makes the domain explicit. Even without reading the schema, an agent knows exactly what artifact this tool creates.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description provides clear context for when to use the tool: creating a new move, with campaignId required. It also gives an important exclusion (parentId excludes sessionId) and a caller restriction (GM-only: campaign owner or accepted gamemaster). However, it does not explicitly name alternatives such as play_update_move for editing existing moves, so it falls just short of the top bar.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

play_create_pageCreate a pageAInspect

Create a new page. Required: name. Set documentType: 'player-recap' and ref: { refType: 'session', refId: <sessionId> } to make a session recap — play sends notifications to the other campaign players on recap create. Before creating a recap, call play_check_recap_exists first to avoid duplicates.

ParametersJSON Schema
NameRequiredDescriptionDefault
refNoWhat the page is attached to. Required for character notes; optional for free-form pages. Allowed on update too (Mongoose has no immutability constraint), though re-anchoring a page is unusual.
linkNoURL-safe slug. Lowercase letters, numbers, and hyphens only.
nameYesPage name / title. Required.
activeNo
publicNo
summaryNoShort page summary. Max 255 characters.
keywordsNoComma-separated keyword string.
promptIdNoMongo `_id` reference (24-character hex string).
descriptionNoMarkdown body.
documentTypeNoWhat kind of page this is. Defaults to 'generic'. Use 'player-recap' for a session recap.

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.7/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Beyond the annotations, the description discloses a notable side effect: creating a player-recap sends notifications to the other campaign players. It also warns about duplicate recaps, which is valuable non-obvious behavior for a create operation.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is three tight sentences with no filler. The required field is front-loaded, the recap configuration is given next, and the duplicate-check warning closes it; every sentence earns its place.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given a rich schema, an output schema, and annotations that already signal mutability and open-world behavior, this description covers the main creation path and the special recap path. The only meaningful operation-specific guidance an agent needs is the duplicate check, which is included.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

With 80% schema coverage, the schema already handles most parameter meaning. The description adds essential cross-parameter semantics by explaining that documentType: 'player-recap' plus ref { refType: 'session', refId: <sessionId> } triggers the recap notification behavior, which the schema alone does not convey.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description opens with 'Create a new page', a specific verb and resource, and clearly distinguishes this creation tool from siblings like play_update_page and play_delete_page. It further sharpens purpose by explaining the session-recap creation path.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description gives explicit guidance for the recap use case: set documentType and ref, and call play_check_recap_exists first to avoid duplicates. It does not explicitly contrast with play_update_page, but the create-vs-update distinction is strongly implied and the recap workflow is well covered.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

play_create_sessionCreate a sessionAInspect

Create a new session for a campaign. Required: campaignId and date (dd/mm/yy format). Other fields (name, description, planned battlemaps) are optional and pass through to play, which authorizes the caller via campaign 'contribute' permission.

ParametersJSON Schema
NameRequiredDescriptionDefault
dateYesPlanned or actual session date in `dd/mm/yy` format. Required.
nameNoSession name / title.
imageNo
statusNo
summaryNoShort session summary. Max 150 characters.
battlemapsNo
campaignIdYesCampaign the session belongs to. Required.
charactersNo
descriptionNoSession body / notes / recap. Markdown supported.
sessionImagesNo

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

The annotations are only false hints, so the description carries the behavioral burden. It adds valuable context: optional fields pass through to play and the caller must be authorized via the campaign 'contribute' permission. There is no contradiction with the annotations.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two sentences with no filler. The create action, required inputs, optional fields, and authorization behavior are all front-loaded, and every sentence contributes useful information.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness3/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

The description is enough to make a basic create call and an output schema exists, but with 10 parameters and 50% schema coverage, several optional fields remain unexplained. It is minimally viable but leaves gaps around parameter meaning and alternative session operations.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters2/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is only 50%, and the description does not compensate for the undocumented parameters. It names campaignId, date, name, description, and battlemaps, but leaves image, status, characters, and sessionImages unexplained. It mostly restates requiredness and date format already present in the schema.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description opens with 'Create a new session for a campaign,' giving a specific verb and resource. The sibling list includes play_get_session, play_update_session, and play_delete_session, so the create intent is unambiguous without needing to inspect schemas.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description clearly states the required arguments (campaignId and date), marks the rest as optional, and mentions the 'contribute' permission precondition. It does not explicitly contrast with play_update_session or play_delete_session, but the usage context for a create operation is clear.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

play_decline_friend_requestDecline a friend requestA
DestructiveIdempotent
Inspect

Decline a pending friend request directed at the calling user. Pass friendId from play_list_pending_friends.

ParametersJSON Schema
NameRequiredDescriptionDefault
friendIdYes`_id` of the friend record on the calling user's friends list. NOT the other user's id. Use play_list_pending_friends (for accept/decline) or play_list_my_friends (for remove) to obtain it.

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.5/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare destructiveHint=true and readOnlyHint=false, covering the mutation nature. The description adds the constraint that the request must be pending and directed at the calling user, and specifies the exact source for the ID, giving operational context beyond the safety hints.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two sentences with no filler: the first states the purpose, the second tells how to obtain the parameter. Purpose is front-loaded and every word earns its place.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

This is a simple one-parameter tool with an output schema present. The description covers the operation, the origin of the required ID, and implicitly its scope (pending, calling user). Nothing essential for correct invocation is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, and the parameter description already includes the 'NOT the other user's id' clarification and the list-source guidance. The tool description's mention of friendId from play_list_pending_friends is redundant with the schema, so it adds minimal new meaning beyond what the schema provides.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states a specific verb ('Decline') and resource ('pending friend request') scoped to the calling user, and the qualifier 'pending' plus the source list clearly differentiates it from accept, cancel, and remove siblings. An agent knows exactly what this tool does and how it differs from peers.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It explicitly instructs to pass friendId from play_list_pending_friends, and the schema description reinforces that play_list_pending_friends is for accept/decline while play_list_my_friends is for remove, effectively routing the agent to the correct list and tool for this operation.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

play_delete_campaignDelete a play campaignA
DestructiveIdempotent
Inspect

Permanently delete a campaign by id. Removes all of its sessions, invites, and members. Caller must have campaign 'delete' permission (typically the owning DM). Destructive. Confirm with the user first.

ParametersJSON Schema
NameRequiredDescriptionDefault
idYesMongo `_id` of the campaign.

Output Schema

ParametersJSON Schema
NameRequiredDescription
idNo
deletedNo

TDQS

A4.5/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already flag destructiveHint=true, but the description adds crucial context beyond that: the operation is permanent, cascades to sessions/invites/members, requires specific permissions, and mandates user confirmation. This is exactly the behavioral disclosure an agent needs for a destructive call.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Three short sentences, each earning its place: core action, cascade consequences, then permission and safety guidance. Front-loaded with the verb-resource pair and no wasted words.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a one-parameter destructive operation with an output schema, the description covers what gets destroyed, the permission prerequisite, and the confirmation requirement. Nothing essential is missing for an agent to invoke it correctly.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100% with the single parameter id already documented as 'Mongo _id of the campaign.' The description adds no new meaning about the parameter itself, and the baseline 3 is appropriate when the schema carries the full weight.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description opens with 'Permanently delete a campaign by id', using a specific verb and resource, and clearly distinguishes this from sibling delete tools for sessions, characters, pages, and moves. The cascade effect ('Removes all of its sessions, invites, and members') further defines the scope unambiguously.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description provides actionable when-to-use context: the caller must hold campaign 'delete' permission (typically the owning DM), and the agent is instructed to confirm with the user first. It doesn't explicitly name alternatives, but the resource is unique among siblings, so no exclusion is strictly needed.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

play_delete_characterDetach a character from playA
DestructiveIdempotent
Inspect

Detach a character from play's tracking. Removes any campaign references but does NOT delete the underlying vault character document. Caller must own the character or have admin role.

ParametersJSON Schema
NameRequiredDescriptionDefault
idYesMongo `_id` of the play character record.

Output Schema

ParametersJSON Schema
NameRequiredDescription
idNo
deletedNo

TDQS

A4.3/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already flag destructiveHint=true and idempotentHint=true, so the description carries a lower burden but still adds genuine value: it scopes the destruction ('removes campaign references but does NOT delete the underlying vault character document') and discloses the permission requirement. This is exactly the contextual enrichment the rubric asks for beyond annotations.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Three sentences, each earning its place: the core action, the scope boundary, and the permission gate. No filler, no repetition of schema content, no vague boilerplate.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a single-parameter tool with 100% schema coverage, a full set of annotations, and an output schema present, the description covers everything an agent needs: what is affected, what is spared, and who is allowed to invoke it. Nothing material is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%: the sole parameter `id` is already fully documented as 'Mongo `_id` of the play character record.' The description contributes no additional parameter syntax, format, or constraint details, so the schema carries the heavy lifting and the baseline of 3 applies.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description uses a specific verb-plus-resource construction ('Detach a character from play's tracking') and draws an explicit boundary against the destructive sibling 'vault_delete_character' by stating it does NOT delete the underlying vault document. An agent can immediately distinguish this from the many similar play_/vault_ tools.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description gives clear invocation context: it names exactly what the operation does and doesn't do, which implicitly tells the agent when this tool is appropriate (detach tracking) versus deletion tools. The ownership/admin prerequisite is a concrete when-to-call condition. However, it never names a sibling alternative explicitly to complete the when/when-not guidance.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

play_delete_moveDelete a moveA
DestructiveIdempotent
Inspect

Permanently delete a move by id. Its child moves are detached back into the feed, not deleted. GM-only. Destructive — the move's collated round text is lost. Confirm with the user first.

ParametersJSON Schema
NameRequiredDescriptionDefault
idYesMongo `_id` of the move.

Output Schema

ParametersJSON Schema
NameRequiredDescription
idNo
deletedNo

TDQS

A4.5/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Beyond the annotations (destructiveHint=true, idempotentHint=true), the description adds substantial behavioral detail: deletion is permanent, collated round text is lost, child moves are detached back into the feed, and operator authorization is GM-only. This is exactly the context needed to use a destructive tool safely.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Three short sentences, each carrying essential information: the core operation, the side-effect on child moves, and the authorization/destructive warning. Nothing is redundant or padded.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With one fully documented parameter, a provided output schema, and rich annotations, the description still adds all necessary behavioral context: permanence, child-move behavior, GM restriction, lost text, and user confirmation. No relevant gap remains.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%: the only parameter, id, is already described as the Mongo _id of the move. The description confirms deletion happens 'by id' but adds no new parameter-level meaning beyond the schema.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description names a specific verb and resource: permanently delete a move by its id. It also states the key nuance—child moves are detached, not deleted—which distinguishes it from related move/session tools.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description clearly states when it applies (GM-only) and instructs the agent to confirm with the user first, which is critical usage guidance. It doesn't explicitly mention alternatives or excluded cases, but the GM-only gate and destructive warning provide clear context.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

play_delete_pageDelete a pageA
DestructiveIdempotent
Inspect

Soft-delete a page by id (30-day TTL via deactivated_at, recoverable in the app UI within the window). Owner or admin only. Destructive. Confirm with the user first.

ParametersJSON Schema
NameRequiredDescriptionDefault
idYesMongo `_id` of the page.

Output Schema

ParametersJSON Schema
NameRequiredDescription
idNo
deletedNo

TDQS

A4.5/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

The description goes far beyond the annotations by explaining that deletion is soft (30-day TTL via deactivated_at), recoverable in the UI, and permission-restricted. This adds significant behavioral context despite destructiveHint and idempotentHint already being present.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Three compact sentences, each carrying distinct information: operation, TTL/recovery, and authorization/confirmation requirements. No filler or redundant phrasing.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a single-parameter tool with a full input schema and an output schema present, the description covers the essential decision factors: permission, destructiveness, confirmation, recovery, and soft-delete window. Nothing critical is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The schema fully documents the only parameter (Mongo _id of the page, minLength 1, required). The description merely repeats 'by id' without adding parameter-specific details, so it stays at the baseline for high schema coverage.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a precise action ('soft-delete a page by id'), the resource type, and key semantics (30-day TTL, recoverable). This clearly distinguishes it from hard-delete or other delete tools in the sibling list.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Provides clear context on when it is appropriate to call: only for pages, owner/admin only, and with explicit user confirmation. It does not name alternatives like play_update_page or imagine_delete_world_page, but the conditions for use are explicit enough to prevent misuse.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

play_delete_sessionDelete a sessionA
DestructiveIdempotent
Inspect

Permanently delete a session by id, including its notes and any session-image / battlemap attachments. Caller must have session 'contribute' permission. Destructive. Confirm with the user first.

ParametersJSON Schema
NameRequiredDescriptionDefault
idYesMongo `_id` of the session.

Output Schema

ParametersJSON Schema
NameRequiredDescription
idNo
deletedNo

TDQS

A4.5/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already signal destructive and read-only status, but the description adds concrete side effects (notes, session-image/battlemap attachments destroyed) and the permission requirement. This is exactly the extra context the rubric rewards.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Three short sentences, front-loaded with the main action and scope, then permissions and confirmation. Every clause adds a new piece of information with no redundancy.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

A single parameter, a clear side-effect list, permission requirements, and confirmation guidance make the description self-sufficient. The output schema exists, so return-value details are unnecessary.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The schema covers 100% of the single id parameter with a description ('Mongo _id of the session'). The description repeats 'by id' but does not deepen the semantics, so baseline 3 is appropriate.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

Clearly states the specific action ('delete'), the resource ('session'), and the identifier ('by id'), and enumerates included side effects like notes and attachments. This distinguishes it from sibling delete tools by naming the exact resource type.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Provides clear context: the required permission ('contribute') and the instruction to confirm with the user first. It does not explicitly list when-not-to-use or name alternative tools, so it stops short of the 5 threshold.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

play_disable_pbem_inboxDisable a campaign's PBEM inboxA
Idempotent
Inspect

Disable the inbox: mail to the campaign's address stops routing (bounces at the webhook). The address is kept and re-enables unchanged. GM-only.

ParametersJSON Schema
NameRequiredDescriptionDefault
campaignIdYesMongo `_id` of the play campaign.

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.5/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Beyond the annotations, the description explains what actually happens: mail stops routing, bounces at the webhook, and the address is kept and can be re-enabled unchanged. This aligns with destructiveHint=false and idempotentHint=true while adding meaningful operational detail.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Three short sentences deliver the action, the behavioral consequence, the preserved state, and the permission requirement. Every sentence earns its place and the key action is front-loaded.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a one-parameter tool with an output schema and supportive annotations, this description is complete: it states who can use it, what happens to incoming mail, and what happens to the address. No critical decision-making information is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so the single campaignId parameter is already fully documented in the schema. The description adds no additional parameter-level meaning beyond tying the action to 'the campaign's address,' which is appropriate given the baseline.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states a specific verb and resource: 'Disable the inbox' for a campaign's PBEM inbox. It also clarifies the concrete consequence—mail stops routing and bounces—and the retained address, clearly distinguishing it from enable or regenerate operations.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description gives clear context: use this when you want to disable a campaign's PBEM inbox while keeping the address, and it explicitly restricts usage to GMs. It does not explicitly name the sibling enable tool, but 're-enables unchanged' strongly implies the counterpart operation.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

play_dismiss_pbem_emailDismiss a PBEM inbox emailA
Idempotent
Inspect

Mark an inbox email dismissed (misdirected mail, noise). The item is retained with status 'dismissed', not deleted. GM-only.

ParametersJSON Schema
NameRequiredDescriptionDefault
itemIdYesMongo `_id` of the inbox item.

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.3/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

The description adds specific behavioral detail beyond what annotations already provide: the item is retained, its status becomes 'dismissed', and it is not deleted. It also discloses the GM-only permission requirement, which is not present in annotations or schema. The description aligns with destructiveHint=false and idempotentHint=true, with no contradiction.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is extremely concise: two sentences, no filler, and every element earns its place. The action is front-loaded, followed by the retention behavior and the GM-only restriction. This is efficient and easy for an agent to parse.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a simple one-parameter tool with full schema coverage, annotations, and an output schema present, the description covers the action, the state change, the non-destructive nature, and the required role. Nothing essential is missing for correct invocation.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, and the single parameter itemId is already described as the Mongo _id of the inbox item. The description does not add further parameter-level detail, but since the schema fully documents the parameter, no additional compensation is required. Baseline 3 is appropriate.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states a specific verb and resource: 'Mark an inbox email dismissed'. It also clarifies the purpose (misdirected mail, noise) and distinguishes the action from deletion by adding 'retained with status dismissed, not deleted'. This is clear and differentiates the tool from related PBEM email operations.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description gives clear context for when to use the tool (misdirected/noise emails) and an access restriction ('GM-only'). It does not explicitly name alternative tools like play_resolve_pbem_email or state when not to use it, but the context is sufficient for an agent to make a reasonable choice.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

play_enable_pbem_inboxEnable a campaign's PBEM inboxA
Idempotent
Inspect

Enable the play-by-email inbox on a campaign. Mints the campaign's unique inbound address on first enable (subsequent enables keep the existing address). Returns the pbem block including the address players CC. GM-only.

ParametersJSON Schema
NameRequiredDescriptionDefault
campaignIdYesMongo `_id` of the play campaign.

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.5/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

The description goes well beyond the annotations by revealing that the first enable mints a unique inbound address, that subsequent enables preserve it, and that the return block contains the address players CC. It also discloses the GM-only access restriction. No contradiction with the idempotentHint annotation.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Three dense sentences with the core purpose front-loaded offense, followed by the most decision-relevant behavior and access restriction. Every sentence adds value with no filler.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a one-parameter tool with a rich output schema and annotations, the description provides the required accessibility role, idempotence behavior, return-value context, and parameter context. Nothing essential is missing for correct invocation.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The schema already fully documents the single parameter as the Mongo _id of the play campaign, so the description does not need to add much. It only reinforces that the action targets a campaign, which is adequate given 100% schema description coverage.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states a precise action ('Enable the play-by-email inbox') on a clear resource ('a campaign') and adds distinctive details about address minting. This distinguishes it from related siblings like play_disable_pbem_inbox and play_regenerate_pbem_address.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It clearly specifies that this is a GM-only operation and describes what happens on repeated enables. It does not explicitly compare against sibling PBEM tools such as play_regenerate_pbem_address or play_consume_pbem_emails, but the intended invocation context is clear.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

play_find_friendFind a friend by name or emailA
Read-onlyIdempotent
Inspect

Search the play user directory by name or email substring. Used to locate a user before sending a friend request. Rate-limited by play to deter scraping.

ParametersJSON Schema
NameRequiredDescriptionDefault
queryYesSubstring to search names and emails against. Required.

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.3/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already provide the safety profile (readOnlyHint=true, idempotentHint=true, destructiveHint=false). The description adds non-obvious behavioral context beyond that: substring matching over names and emails, and rate-limiting imposed by the platform to deter scraping. This is useful operational information.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Three sentences, each earning its place: the main action, the motivating use case, and a rate-limit caution. The verb and resource are front-loaded, and there is no filler or redundant restatement of the title.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a single-parameter, read-only search tool with an output schema present, the description covers what the tool does, why an agent would use it, and a key operational caveat. Nothing an agent needs to decide whether to call it is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%: the query parameter is documented as 'Substring to search names and emails against.' The description essentially restates this scope, only adding that the search targets the 'play user directory.' With high schema coverage, the description need not add much parameter-level detail.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description opens with a specific verb and resource: 'Search the play user directory by name or email substring.' This clearly identifies the tool as a lookup operation and distinguishes it from sibling tools like play_send_friend_request or play_list_my_friends, since it is the discovery step rather than the action step.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description states a concrete use case: 'Used to locate a user before sending a friend request.' This gives clear context for when to call the tool. It does not explicitly name alternatives or exclusions, but the intended position in the friend-request workflow is unambiguous.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

play_get_campaignGet a play campaignA
Read-onlyIdempotent
Inspect

Fetch one campaign by id, including settings and any DM/player metadata. Calling user must be a member (DM or player). The campaign's ruleset-specific material lives in its legs array — one entry per ruleset, each carrying { ruleset, active, rules, items, spells, characters }; inactive legs are hidden from normal UI but never deleted. There is no campaign-level ruleset field. Defaults to a summary shape: each leg's raw rule/item/spell ObjectId arrays are replaced with resolved [{ _id, name }, ...] lists the LLM can act on. Pass detail: 'full' to receive the raw ObjectId arrays instead. Each leg's rules, items, and spells are the campaign's house rules in that leg's ruleset. The response's imagineWorldIds and imagineAdventures ([{ id, name }, ...], each adventure's current name) list the Imagine worlds and adventures linked to this campaign; they are read from the worlds' and adventures' own links and are read-only here (change them with the imagine link/unlink tools). The imagineAdventures ids are the valid values for a session's imagineAdventureId tag.

ParametersJSON Schema
NameRequiredDescriptionDefault
idYesMongo `_id` of the campaign.
detailNoResponse shape. 'summary' (default) trims raw-ObjectId arrays and full character sheets to a compact LLM-friendly form; 'full' returns the populated document with every field inline.summary

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.6/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With annotations already covering readOnlyHint, idempotentHint, and destructiveHint, the description adds rich non-obvious behavior: inactive legs are 'hidden from normal UI but never deleted,' there is 'no campaign-level ruleset field,' the summary shape transforms raw ObjectId arrays into resolved [{_id, name}] lists, and imagineWorldIds/imagineAdventures are derived from other objects' links and are read-only here. These disclosures go well beyond the structured annotations.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is long but every sentence carries a distinct fact: precondition, legs structure, hidden-leg behavior, absence of a campaign-level ruleset, detail-mode transform, house-rules semantics, and cross-tool read-only fields. It is front-loaded with the core purpose. It loses half a point because the detail-mode explanation partly repeats the schema's parameter description.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Despite the tool's complexity — nested legs, dual response modes, derived imagine fields, and cross-tool data flows — nothing an agent needs is missing: membership prerequisite, id semantics, detail behavior, response shape, and downstream linkage (imagineAdventures ids are the valid values for a session's imagineAdventureId). The output schema covers raw return structure, and the description covers everything else.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, so the baseline is 3. The description adds meaningful value by specifying exactly what the detail modes produce: summary replaces raw rule/item/spell ObjectId arrays with resolved [{ _id, name }, ...] lists 'the LLM can act on,' while full returns the raw ObjectId arrays. It also clarifies that the id parameter selects a campaign the caller must belong to. This exceeds the schema's terse wording.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The opening sentence is precise: 'Fetch one campaign by id, including settings and any DM/player metadata.' It names a specific verb, a specific resource (campaign), and a retrieval key, and it is clearly distinct from sibling list tools (play_list_my_campaigns) and other get-one tools (play_get_session, play_get_move).

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description states an explicit precondition ('Calling user must be a member (DM or player)') and routes mutations of the imagine fields to named alternatives ('change them with the imagine link/unlink tools'). It also guides the detail-mode choice. It stops short of an explicit when-to-use vs play_list_my_campaigns distinction, but that is strongly implied by 'Fetch one campaign by id.'

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

play_get_character_noteGet a character note (DM or player)A
Idempotent
Inspect

Fetch the DM-side or player-side note attached to a play character. Lazy-creates the note on first read if absent, so this endpoint always returns a note. Authorization runs through the character's campaign permission.

ParametersJSON Schema
NameRequiredDescriptionDefault
characterIdYesMongo `_id` of the play character (NOT the vault character id).
documentTypeYesWhich note to fetch: 'dm-notes' (GM-only) or 'player-notes' (visible to the campaign).

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.3/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

The description adds valuable behavior beyond the annotations: it discloses the lazy-creation side effect on first read ('Lazy-creates the note on first read if absent'), explains why the endpoint always returns a note, and states the authorization model. This is especially useful given readOnlyHint is false and idempotentHint is true—the description coherently explains both annotation signals.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two tight sentences deliver the core purpose, the lazy-creation behavior, and the authorization model with no filler. The most important differentiator (fetch vs. note type) is front-loaded.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a two-parameter getter with an output schema, the description covers everything an agent needs to invoke it correctly: what it returns, side effects, auth requirements, and required parameters. The presence of an output schema means return-shape details need not be repeated in the description.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%: both characterId and documentType have clear descriptions, including the 'NOT the vault character id' warning and the dm-notes/player-notes enum semantics. The description adds no parameter-level detail beyond the schema, which is acceptable given the schema already carries the heavy lifting.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description opens with a specific verb ('Fetch') and a precise resource ('DM-side or player-side note attached to a play character'), distinguishing the read operation from the related sibling play_update_character_note. It also clarifies the two note variants, leaving no ambiguity about what is retrieved.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description implies this is the read path for character notes and even notes the authorization context ('campaign permission'), but it does not explicitly state when to prefer it over alternatives or when not to use it. There is no direct referral to play_update_character_note for modifying notes, so usage guidance is implied rather than explicit.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

play_get_moveGet a moveA
Read-onlyIdempotent
Inspect

Fetch one move by id, including its full markdown body, plus a children array of its child scenes (split party) filtered to the caller's visibility. A restricted move reads as 404 for players not on its list. Caller must be a member of the move's campaign (any member of a public campaign).

ParametersJSON Schema
NameRequiredDescriptionDefault
idYesMongo `_id` of the move.

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.5/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Beyond the readOnly/idempotent/destructive annotations, it discloses important behavior: visibility filtering of child scenes, restricted moves returning 404 to unauthorized players, and campaign membership requirements. No contradiction with annotations exists.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two sentences carry all necessary information with no filler. The core behavior is front-loaded, followed by return details and then authorization/error behavior.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a single-parameter read operation with an output schema and read-only annotations, the description covers the essential non-schema facts: payload contents, visibility filtering, 404 semantics, and membership restrictions. Nothing needed for correct invocation is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The single parameter has 100% schema description coverage, so the schema already documents id as a Mongo _id. The description only repeats that this is a by-id fetch and adds no new parameter-level meaning, which matches the baseline for fully covered schemas.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description names a specific verb and resource: 'Fetch one move by id'. It also details what is returned (full markdown body and a children array), which distinguishes it from sibling list tools like play_list_campaign_moves and play_list_session_moves.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description clearly implies when to use it: when you have a move's id and need the full move object or its child scenes. It also gives access context by requiring caller membership in the campaign. It does not explicitly name alternative list tools, so it stops short of a 5.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

play_get_pageGet a pageA
Read-onlyIdempotent
Inspect

Fetch one page by id, including its full markdown body. Caller must be the owner, an admin, or the page must be public.

ParametersJSON Schema
NameRequiredDescriptionDefault
idYesMongo `_id` of the page.

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.3/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already indicate readOnlyHint, idempotentHint, and non-destructive behavior, so the safety profile is covered. The description adds useful context beyond annotations by specifying the access control requirement and the full markdown body in the response.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two tight sentences with zero filler. The primary action is front-loaded, and the access requirement is stated in a single follow-up clause.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a one-parameter read tool with full annotations and an output schema, the description is complete. It clarifies what is returned, how to identify the resource, and who is allowed to call it—nothing essential is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100% and the id parameter is already documented as the Mongo _id of the page. The description only repeats 'by id' without adding format, validation, or behavior details, so it does not elevate above the schema baseline.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource: 'Fetch one page by id' with the distinctive detail that it includes the full markdown body. This clearly distinguishes it from list-style siblings like play_list_pages and from getters for other resource types.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description makes the core usage context clear—retrieve a single page by id—and adds the access precondition (owner, admin, or public). It does not explicitly name alternative tools or say when not to use it, but the id-based single-resource purpose is unambiguous.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

play_get_sessionGet a sessionA
Read-onlyIdempotent
Inspect

Fetch one session by id, including its notes, battlemap references, and session-image attachments. Caller must be a member of the session's campaign.

ParametersJSON Schema
NameRequiredDescriptionDefault
idYesMongo `_id` of the session.

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint=true, destructiveHint=false, and idempotentHint=true, so the description does not need to restate those. The description adds a useful behavioral detail: the caller must be a member of the session's campaign, which is a permission requirement not covered by annotations. However, it does not disclose other behavioral aspects like return format or potential errors, but annotations cover the safety profile.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is two concise sentences, with the key action and object front-loaded. The second sentence adds a necessary permission note. No extraneous words or redundant information.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the tool's simplicity (single parameter) and the presence of a rich output schema (as indicated by has_output_schema=true), the description is sufficient for an agent to call it correctly. The permission requirement is a key contextual element. The only minor gap is not specifying that the output schema provides the return structure, but that is expected.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The schema covers 100% of parameters with a description for 'id', so the description does not need to add much. The description implies the ID refers to a session and that it is the primary key, which is consistent with the schema. No extra nuance is provided that isn't already in the schema.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states a specific verb ('Fetch'), resource ('one session by id'), and scope ('including its notes, battlemap references, and session-image attachments'). It is clear and distinct from siblings like play_get_page or play_list_campaign_sessions, which serve different purposes.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description clearly states the primary use case (fetching a session by ID) and implies it should be used when a specific session is needed, rather than listing sessions (play_list_campaign_sessions). However, it does not explicitly state when not to use it or name alternatives, but the context is clear enough.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

play_invite_campaign_playerInvite a player to a campaignBInspect

Send a campaign invite to another user. Caller must have 'contribute' on the campaign. Play rate-limits this endpoint (per-caller and per-campaign) to deter spam.

ParametersJSON Schema
NameRequiredDescriptionDefault
roleNoRole to invite the user as. 'player' is the default and almost always what you want; 'watcher' is read-only; 'gamemaster' grants co-DM permissions.player
userIdYesUser id of the invitee. Required. Pair with play_find_friend if you only have a name or email; invite-by-email is not supported at this endpoint.
campaignIdYesCampaign id.

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

B3.3/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations are all false (readOnlyHint=false, etc.), so the description carries the burden of behavioral disclosure. It adds useful context: the call requires 'contribute' permission and is rate-limited per caller and per campaign. However, it does not mention that the invite creates a pending state that the invitee must accept, nor does it describe any side effects beyond sending the invite. It does not contradict the annotations, so a mid-range score is appropriate.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is two sentences with zero fluff. The first sentence states the primary action, and the second provides two critical constraints (permission and rate limiting). Every word contributes to the agent's decision-making. It is perfectly front-loaded and appropriate in length.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness3/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

The description covers the core action and constraints but omits some operational context that an agent might need, such as whether the invitee must be a friend or what happens if the user is already in the campaign. The existence of an output schema reduces the need to explain return values, but the description could still benefit from noting that the invite is pending until accepted. Overall, it's adequate but not exhaustive.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so all three parameters have descriptions in the schema itself. The tool description adds no additional parameter meaning; it merely restates the permission requirement and rate limit. Since the schema already documents the role enum and the userId/campaignId semantics, the description provides no extra value for parameter understanding, warranting the baseline score of 3.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the action: 'Send a campaign invite to another user.' It identifies the resource (campaign invite) and the target (another user). It does not explicitly differentiate from sibling tools like play_respond_to_campaign_invite, but those are distinct enough in name and action. The permission requirement adds specificity, but the description could be stronger by naming the closest sibling alternative.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines2/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description does not mention when to use this tool versus alternatives. It only states a prerequisite (caller must have 'contribute') and a rate-limit caveat. There is no guidance on when not to use it, such as 'For invite-by-email, use play_find_friend first' (though that hint exists in the schema). The absence of any sibling comparison or exclusions leaves the agent without explicit routing context.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

play_list_campaign_charactersList characters in a campaignA
Read-onlyIdempotent
Inspect

List the characters participating in a play campaign. Returns play-side character refs; pair with vault_get_character for full character data. Defaults to a summary shape (id, name, image, npc flag, short description); pass detail: 'full' to receive each character's full vault sheet inline.

ParametersJSON Schema
NameRequiredDescriptionDefault
detailNoResponse shape. 'summary' (default) trims raw-ObjectId arrays and full character sheets to a compact LLM-friendly form; 'full' returns the populated document with every field inline.summary
campaignIdYesMongo `_id` of the campaign.

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.3/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint, idempotentHint, and destructiveHint, covering the safety profile. The description adds valuable behavior beyond that: the default summary shape, the option to request 'full' vault sheets inline, and the note that results are play-side refs. No contradictions with annotations.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two sentences, no filler. The core action and resource come first, followed by the key pairing guidance and the default-vs-full behavior, all in under 50 words.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

A simple list-style tool with an output schema, full parameter coverage, and safety annotations. The description covers what the agent needs: what it lists, how to get full character data, and the optional detail behavior. Nothing essential is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so both campaignId and detail are already well documented in the schema. The description adds a tiny bit of context about output shape but does not meaningfully expand parameter semantics beyond what the schema provides.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the verb ('List') and resource ('characters participating in a play campaign'), and clarifies that these are play-side character refs rather than full vault data. This distinguishes it from related tools like vault_get_character or play_list_my_characters.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description gives actionable context: use this to list campaign character refs, then pair with vault_get_character for full data. It doesn't explicitly name alternatives or when-not-to-use conditions, but the pairing guidance effectively routes the agent to the correct workflow.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

play_list_campaign_companionsList companions in a campaignA
Read-onlyIdempotent
Inspect

List the companions (buddies) attached to a play campaign's characters — the supporting cast a table sees beyond the roster. Read-only; the tie itself is managed on the vault character sheet (vault_attach_companion / vault_detach_companion). Monster-typed companions are excluded server-side. One entry per (Main, companion) pair, so a companion linked by two characters appears twice; each entry carries companionOf: { characterId, name, userId } naming the character it accompanies, plus display fields (name, type, ruleset, image, description) and a projected primaryToken slice or null. Pair with vault_get_character on companionCharacterId for the companion's full sheet.

ParametersJSON Schema
NameRequiredDescriptionDefault
campaignIdYesMongo `_id` of the campaign.

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.7/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint=true, idempotentHint=true, and destructiveHint=false, so the safety profile is covered. The description adds substantial behavioral context beyond annotations: monster-typed companions are excluded server-side, one entry exists per (Main, companion) pair so duplicates appear, and each entry contains companionOf plus display fields and a projected primaryToken slice or null. This is exactly the kind of nuance agents need.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is dense but every sentence earns its place: it captures purpose, read-only status, tie management, server-side filtering, cardinality, output shape, and a useful follow-up call. The essential identity of the tool is front-loaded in the first sentence, and the additional clauses layer detail without repetition.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the one-parameter schema, rich output schema, and annotations already conveying safety, the description covers all operational behavior an agent needs: duplicate handling, monster exclusion, output fields, and the companionOf structure. It also connects to vault_get_character for deeper retrieval, making the tool fully self-contained in context.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The only parameter, campaignId, has 100% schema coverage with a description identifying it as a Mongo _id. The description does not add input-format detail beyond that, but with a single fully documented parameter there is little left to compensate for. The reference to companionCharacterId is about output pairing, not parameter semantics, so a baseline 3 is appropriate.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states a specific verb and resource: 'List the companions (buddies) attached to a play campaign's characters.' It also distinguishes this from roster listing by calling the result 'the supporting cast a table sees beyond the roster' and by naming the attachment tools vault_attach_companion / vault_detach_companion as managing the tie itself. This leaves no ambiguity about what the tool returns.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description explicitly routes mutation work elsewhere: 'the tie itself is managed on the vault character sheet (vault_attach_companion / vault_detach_companion).' It also recommends pairing with vault_get_character for full companion sheets. This gives clear when-to-use context and names concrete alternatives, even without a separate 'use this when' phrase.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

play_list_campaign_itemsList items allowed in a campaignA
Read-onlyIdempotent
Inspect

List the campaign's house items: the items it holds as active house-rule associations. Subset of the broader vault catalog. Each sits on the leg matching its own ruleset: omit ruleset to list the items across every leg, or set it to scope the list to that one leg.

ParametersJSON Schema
NameRequiredDescriptionDefault
rulesetNoOptional leg filter. Omitted, the list unions entries across every leg of the campaign; set to a ruleset to scope the list to that leg only.
campaignIdYesMongo `_id` of the campaign.

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A3.7/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare the full safety profile (readOnly, idempotent, non-destructive, closed-world), and an output schema exists, so the description's job is to add domain context. It does so by defining the 'house item' subset relative to the broader vault catalog and by explaining the leg/ruleset scoping model, which is real behavioral context beyond the annotations.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two tightly packed sentences with the core purpose front-loaded and the filtering behavior following. Every clause carries meaning, though the ruleset guidance is somewhat duplicated from the schema, which costs a point.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With only two parameters, rich annotations, and an output schema, the definition covers what an agent needs: the subset semantics, the leg model, and the filter behavior. Nothing essential is missing, though it could have routed the agent away from the broader vault catalog search tools.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so the schema already documents both parameters. The description's ruleset sentence largely restates the schema's own description of that parameter rather than adding new syntax or edge-case meaning, so the baseline 3 applies.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource ('List the campaign's house items') and clarifies the domain term by defining house items as 'the items it holds as active house-rule associations', which separates it from vault_search_items and play_list_campaign_rules. It does not explicitly name the adjacent sibling tools, so it falls just short of full sibling differentiation.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description gives clear guidance on how to use the optional ruleset filter (omit for all legs, set to scope to one leg), which is genuinely useful usage context. However, it offers no when-to-use comparison against alternatives such as vault_search_items or play_list_campaign_rules; usage is implied rather than routed.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

play_list_campaign_movesList moves in a campaignA
Read-onlyIdempotent
Inspect

List the play-by-email moves of one campaign — the move feed. Sorted by shelf position (order), newest first by default; pass order: 'asc' for reading order. Defaults to a summary shape: each move's description is a ~240-character prose preview (image URLs and [[...]] markers don't count toward the budget) carrying a descriptionTruncated flag; detail: 'full' returns complete bodies. Child moves (split-party scenes) are excluded unless children: true. Restricted moves are server-filtered: players see only moves they're listed on; the GM sees all. Caller must be a member of the campaign.

ParametersJSON Schema
NameRequiredDescriptionDefault
limitNoCap the number of moves returned. Hard-capped at 200 server-side.
orderNo'desc' (default) returns the feed shape — newest shelf position first. 'asc' returns reading order.desc
detailNoResponse shape. 'summary' (default) trims each move's description to a ~240-character prose preview so a long campaign doesn't overflow the tool-result budget — image URLs and [[...]] markers don't count toward the budget and the cut lands on a word boundary — and adds a `descriptionTruncated` boolean flagging whether more remains. 'full' returns complete bodies.summary
childrenNoInclude child moves (split-party scenes). Default false: the feed shape, parentless moves only — children render on their parent's page. Pass true when you need every move, e.g. to pick an append target.
campaignIdYesMongo `_id` of the play campaign.

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.4/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already mark the tool as read-only and idempotent, and the description adds substantial behavioral detail beyond that: server-side restriction filtering by role, default exclusion of child moves, truncation with a descriptionTruncated flag, and GM-versus-player visibility. This gives an agent a realistic model of what the call will return and how permissions affect it.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is front-loaded with the core purpose and then logically covers sorting, response shape, child moves, permissions, and membership. It is dense and occasionally restates schema details, but given the five parameters and nuanced behavior, the length is justified.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a read-only listing tool with an output schema present, the description covers everything needed to call it correctly: default and alternate shapes, ordering, child-move handling, restriction filtering, and the membership prerequisite. No important behavioral gap remains.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The input schema already provides 100% parameter coverage with detailed descriptions, defaults, and enums for order, detail, children, and limit. The tool description largely restates those defaults rather than adding new parameter-level meaning, so the high-coverage baseline of 3 is appropriate.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific action — listing play-by-email moves for a single campaign — and describes the result as 'the move feed', making the resource and scope unambiguous. This clearly separates it from sibling tools like play_get_move, which retrieves a single move, and play_list_session_moves, which is session-scoped.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Provides strong contextual guidance: default feed shape, ordering behavior, full-detail option, child-move inclusion, and the campaign-membership requirement. It does not explicitly name alternative sibling tools or state when to prefer them, so it stops just short of fully explicit routing.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

play_list_campaign_playersList players in a campaignA
Read-onlyIdempotent
Inspect

List the players in a play campaign with their roles, invite status, and any per-player flags.

ParametersJSON Schema
NameRequiredDescriptionDefault
campaignIdYesMongo `_id` of the campaign.

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A3.7/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint=true, idempotentHint=true, and destructiveHint=false, so the safety profile is clear. The description adds the output fields but does not describe behavioral details such as whether pending invites are included, ordering, or authentication requirements. This is acceptable but not a strong addition beyond annotations.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

A single sentence that front-loads the action and resource, then adds the meaningful output components. There is no filler or repetition of schema field names.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a simple read-only list tool with one parameter idempotent to call, the description plus annotations and output schema are sufficient. The agent knows what it lists, what fields are surfaced, and that the call is safe to make.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%: the only parameter, campaignId, is documented as a Mongo `_id`. The description adds no parameter-specific detail, but the schema already carries the full semantic burden, so the baseline of 3 applies.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states a specific verb and resource: 'List the players in a play campaign' and adds the fields returned (roles, invite status, per-player flags). It is clear, but it does not explicitly distinguish itself from sibling tools like play_list_campaign_characters or play_list_campaign_sessions, so it earns a 4 rather than a 5.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The intended use is implied by the name and the one-line description, but there is no explicit guidance about when to use this tool versus other campaign list tools or exclusions. It is not misleading, but it leaves the agent to infer usage from context.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

play_list_campaign_rulesList rules allowed in a campaignA
Read-onlyIdempotent
Inspect

List the campaign's house rules: the rules it holds as active house-rule associations. Subset of the broader vault catalog. Each sits on the leg matching its own ruleset: omit ruleset to list the rules across every leg, or set it to scope the list to that one leg.

ParametersJSON Schema
NameRequiredDescriptionDefault
rulesetNoOptional leg filter. Omitted, the list unions entries across every leg of the campaign; set to a ruleset to scope the list to that leg only.
campaignIdYesMongo `_id` of the campaign.

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A3.5/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint, idempotentHint, and destructiveHint=false, so the safety profile is covered. The description adds the semantic detail that results are 'active house-rule associations' scoped per leg, but nothing about volume, ordering, or permissions beyond that.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Three compact sentences, front-loaded with the core purpose before the leg-scoping detail. Some phrasing ('the rules it holds as active house-rule associations') is mildly redundant but not wasteful.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

An output schema exists, so return values need not be explained, and both parameters are schema-documented. The description covers purpose and the key scoping behavior adequately for a simple two-parameter list tool.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so both parameters are already fully documented in the schema, including the ruleset leg-filter semantics. The description largely restates that same behavior, adding no syntax or format detail beyond the schema.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource ('List the campaign's house rules') and clarifies that these are active house-rule associations, a subset of the broader vault catalog. This distinguishes it from catalog-wide siblings like vault_search_rules and list_rulesets, though it never names those tools directly.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description gives usage context for the ruleset parameter (omit to union all legs, set to scope to one leg), which is genuinely helpful. However, it offers no when-to-use guidance relative to siblings such as play_add_campaign_rule or vault_search_rules.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

play_list_campaign_sessionsList sessions in a campaignA
Read-onlyIdempotent
Inspect

List sessions belonging to one campaign. Caller must be a member of the campaign. Defaults to a compact summary shape ordered by most-recently-updated; pass detail: 'full' for the populated shape.

ParametersJSON Schema
NameRequiredDescriptionDefault
sortNo'recent' (default) orders by updatedAt descending so the freshest sessions come back first; 'date' removes the gateway's `recent` override and defers to the play backend's default ordering for the endpoint.recent
limitNoCap the number of sessions returned. Hard-capped at 200 server-side.
detailNoResponse shape. 'summary' (default) returns id + name + status + date + campaign-ref only; 'full' returns the populated session document including battlemap refs and the full description body.summary
campaignIdYesMongo `_id` of the play campaign.

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.5/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already establish that this is a safe, read-only, idempotent operation. The description adds useful behavioral context beyond those annotations: membership requirement, default compact summary shape, most-recently-updated ordering, and the `detail: 'full'` opt-in for the populated shape.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two sentences, no filler. The action and membership requirement are front-loaded, followed immediately by the most decision-relevant parameter behavior. Every sentence earns its place.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a read-only listing tool with an output schema and full annotations, the description covers the essential operational context: campaign scope, membership precondition, and the shape/ordering defaults. Nothing critical is missing for an agent to invoke this correctly.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, so the schema carries the full parameter documentation. The description complements it by highlighting the practical choice between summary and full shapes and noting the default ordering, which reinforces the meaning of `sort` and `detail` without repeating schema details.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description uses a specific verb and resource ('List sessions') and clearly scopes the operation to one campaign. The title and description together unambiguously distinguish this from sibling list tools like play_list_my_sessions.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description states the key prerequisite ('Caller must be a member of the campaign') and gives clear context on default behavior. It does not explicitly name alternatives or state when not to use it, but the intended use case is clear from the one-campaign scope.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

play_list_campaign_spellsList spells allowed in a campaignA
Read-onlyIdempotent
Inspect

List the campaign's house spells: the spells it holds as active house-rule associations. Subset of the broader vault catalog. Each sits on the leg matching its own ruleset: omit ruleset to list the spells across every leg, or set it to scope the list to that one leg.

ParametersJSON Schema
NameRequiredDescriptionDefault
rulesetNoOptional leg filter. Omitted, the list unions entries across every leg of the campaign; set to a ruleset to scope the list to that leg only.
campaignIdYesMongo `_id` of the campaign.

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A3.5/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint, idempotentHint, and destructiveHint=false, so the safety profile is covered. The description adds the useful structural fact that entries are partitioned by ruleset leg and are a subset of the vault catalog, but says nothing about pagination, ordering, or result size.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Three tight sentences, front-loaded with the core definition before the ruleset scoping detail. Nothing is wasted, though the term 'leg' is used without definition, slightly reducing immediate clarity.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With only two parameters, full schema coverage, and an output schema that carries return values, the description covers what an agent needs to invoke the tool correctly. The remaining gap is the absence of any routing guidance against the large set of sibling list tools.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so both parameters are already documented in the schema. The description's explanation of `ruleset` largely restates the schema's own description, adding no syntax or format detail beyond it, so the baseline 3 applies.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb+resource ('List the campaign's house spells') and clarifies the semantic scope ('active house-rule associations' and 'subset of the broader vault catalog'), which distinguishes it from vault_search_spells. It does not explicitly name a sibling tool, so it falls short of a 5.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description explains how to use the `ruleset` parameter (omit to union all legs, set to scope to one leg), which is usage guidance, but it never says when to choose this tool over the sibling vault_search_spells or how it relates to play_list_campaign_rules. Usage is implied rather than delineated.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

play_list_my_campaignsList campaigns I runA
Read-onlyIdempotent
Inspect

List campaigns where the calling user is the DM/owner. Each campaign's ruleset-specific material lives in its legs array — one entry per ruleset, each carrying { ruleset, active, ... }; there is no campaign-level ruleset field. Defaults to a compact summary shape: identification fields, counts of rules/items/spells/sessions/players/characters, and the character roster (playId + vaultId pairs). Pass detail: 'full' to receive the full campaign documents (raw ObjectId arrays for the legs' allowlists, full descriptions, X-card history).

ParametersJSON Schema
NameRequiredDescriptionDefault
detailNoResponse shape. 'summary' (default) trims raw-ObjectId arrays and full character sheets to a compact LLM-friendly form; 'full' returns the populated document with every field inline.summary

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.8/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Even though readOnlyHint and idempotentHint annotations already establish the safety profile, the description adds important behavioral detail: the `legs` array structure, the absence of a campaign-level ruleset field, and the difference between the default summary shape and `detail: 'full'`. This is exactly the kind of non-obvious behavior an agent needs to interpret results correctly.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is dense but every sentence earns its place: purpose, structural gotcha, default output, and full-output behavior are all covered in two sentences. The most important selection predicate is front-loaded, and no content is wasted on restating the name or obvious schema details.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With only one optional parameter, strong annotations, and an output schema present, the description covers everything needed to select and invoke the tool correctly: ownership filter, response shape, and the key `legs`-array nuance. Nothing essential is missing for an agent to make an informed call.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters5/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, and the schema already describes the `detail` enum. The description goes further by explaining what the summary shape contains (counts plus `playId`/`vaultId` roster pairs) and what full shape adds (raw ObjectId arrays, full descriptions, X-card history). This gives the agent concrete expectations for each parameter value beyond the schema text.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource: 'List campaigns where the calling user is the DM/owner.' This clearly distinguishes the tool from siblings like play_list_participated_campaigns, which would include campaigns the user merely participates in. The title and description align without being tautological.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description clearly defines the selection predicate — campaigns the calling user owns — and explains the summary vs. full output choice, giving the agent enough context to know when it applies. However, it does not explicitly contrast itself with sibling alternatives such as play_list_participated_campaigns or play_get_campaign, so it stops short of full when-to-use/when-not-to-use guidance.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

play_list_my_charactersList my play charactersA
Read-onlyIdempotent
Inspect

List the characters the calling user has in any of their campaigns (DM or player). For a single character's full sheet data, use vault_get_character with the returned id.

ParametersJSON Schema
NameRequiredDescriptionDefault

No parameters

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.5/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint=true, idempotentHint=true, and destructiveHint=false, so the description only needs to add context beyond those. It does this by specifying the caller-scoped nature of the results and the DM-or-player coverage. Mentioning the returned id also implies the output contains character ids usable by vault_get_character, which is helpful.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two crisp sentences with no filler. The primary action is stated first, and the alternative tool reference is placed second. Every sentence earns its place.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a zero-parameter, read-only list tool with an output schema and safety annotations, the description is complete. It tells the agent what results are returned, who they belong to, and how to follow up for full character details.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The input schema has zero parameters, and schema description coverage is 100%, so parameter semantics are trivially satisfied. The baseline of 4 for no-parameter tools applies; the description does not need to add parameter details.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the verb and resource: 'List the characters the calling user has in any of their campaigns (DM or player).' It also distinguishes itself from related tools like vault_get_character by noting that full sheet data belongs there. The scope is explicit and unambiguous.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description gives clear context for when to use this tool versus vault_get_character: for a quick list of a user's characters across campaigns, and for full sheet data use vault_get_character with the returned id. It does not explicitly mention play_list_campaign_characters as an alternative for per-campaign listing, but it provides enough routing guidance to be useful.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

play_list_my_friendsList my friendsA
Read-onlyIdempotent
Inspect

List the calling user's accepted friends. Returns each friend's display name and id, suitable for campaign-invite or friend-lookup workflows.

ParametersJSON Schema
NameRequiredDescriptionDefault

No parameters

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.4/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already indicate read-only, idempotent, and non-destructive. The description adds context about the scope ('calling user's accepted friends') and the return content (display name and id), which is useful beyond the annotations. No contradictions.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is very brief, front-loads the purpose and scope, and adds a single sentence on typical use cases. Every sentence earns its place, with no fluff.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

The tool is simple with no parameters, and the description mentions the return fields (name and id), which is sufficient for an agent to know what to expect. An output schema exists, so detailed return structure is likely covered there. Slightly missing is whether the list is sorted or if pagination applies, but for a simple list tool this is adequate.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

There are zero parameters, and the schema is empty with 100% coverage. The description clarifies the output fields, which helps agents understand what they'll receive, but parameters are nonexistent, so the baseline of 4 (for no params) is appropriate.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the tool lists the calling user's accepted friends, specifies the returned data (display name and id), and mentions intended use cases (campaign-invite or friend-lookup). It is distinct from sibling tools like play_list_pending_friends and play_find_friend.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description implies use for retrieving accepted friends, distinct from pending friend requests (play_list_pending_friends) and searching for specific friends (play_find_friend). However, it doesn't explicitly state when not to use this tool or mention alternatives, but the use-case mention provides decent guidance.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

play_list_my_sessionsList my sessionsA
Read-onlyIdempotent
Inspect

List sessions the calling user is part of across all their campaigns (DM or player). Defaults to a compact summary shape ordered by most-recently-updated. Pass detail: 'full' to receive the populated session document (battlemap refs, full description). Use limit to cap the array size.

ParametersJSON Schema
NameRequiredDescriptionDefault
sortNo'recent' (default) orders by updatedAt descending so the freshest sessions come back first; 'date' removes the gateway's `recent` override and defers to the play backend's default ordering for the endpoint.recent
limitNoCap the number of sessions returned. Hard-capped at 200 server-side.
detailNoResponse shape. 'summary' (default) returns id + name + status + date + campaign-ref only; 'full' returns the populated session document including battlemap refs and the full description body.summary

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.3/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already mark the tool read-only and idempotent; the description adds non-obvious behavior: the response defaults to a compact summary shape, is ordered by most-recently-updated, and can be expanded via detail='full' to include battlemap refs and full descriptions. It does not mention the sort='date' option, but the schema covers it.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Three compact sentences, front-loaded with the core purpose, then defaults, then configuration options. Every sentence adds information and there is no filler.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a read-only list tool with an output schema, 100% schema coverage, and clear annotations, this description provides all selection and invocation context: scope, default ordering, response shape, and how to request full detail or cap results. Nothing material is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, with every parameter (sort, limit, detail) already described in the input schema. The description reinforces detail and limit but adds no new parameter semantics beyond the schema, so the baseline 3 applies.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description opens with a clear verb and resource: 'List sessions the calling user is part of across all their campaigns (DM or player).' This scope distinguishes it from sibling tools like play_list_campaign_sessions (campaign-scoped) and play_get_session (single session).

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It clearly states this is the cross-campaign, user-centric listing tool ('across all their campaigns'), which implies when to prefer it over campaign-scoped alternatives. However, it does not explicitly name a sibling or state when not to use it, so it stops short of a 5.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

play_list_pagesList play pagesA
Read-onlyIdempotent
Inspect

List play pages, optionally filtered by what they're attached to and/or by documentType. To find session recaps, pass refType: 'session', refId: '<sessionId>', documentType: 'player-recap'. Defaults to a compact summary shape; pass detail: 'full' for the page body markdown inline.

ParametersJSON Schema
NameRequiredDescriptionDefault
refIdNoFilter pages by the referenced entity's Mongo `_id`. Pair with `refType` to scope the lookup.
detailNoResponse shape. 'summary' (default) drops the markdown `description` body and trims the owner populate, keeping identification + `ref` + `documentType` + the short `summary` field. 'full' returns the populated page document including the full body.summary
refTypeNoFilter pages by the entity type they reference. One of: campaign, session, character.
documentTypeNoFilter pages by documentType: 'player-recap' (session recap), 'dm-notes' / 'player-notes' (character-attached notes), 'campaign-logistics' (the campaign's one logistics page, managed by its own endpoint), or 'generic' (free-form).

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.4/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint=true, idempotentHint=true, and destructiveHint=false, so the safety profile is covered. The description adds useful behavioral detail beyond the annotations by explaining the default compact summary shape and the effect of passing 'full' for the page body markdown, which helps the agent anticipate response behavior.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Three sentences with no fluff: the main action and filters come first, followed by a concrete recipe for the most likely use case, then the key response-shape toggle. Every sentence earns its place and the most important information is front-loaded.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a read-only list tool with four optional parameters, full schema coverage, and an output schema, the description covers the essential invocation patterns, the filter semantics, and the response-shape choice. There are no required parameters or hidden gotchas left unexplained.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters5/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, but the description goes further by clarifying that refId/refType constitute 'what they're attached to' and by giving an exact, actionable example for finding session recaps. It also interprets the 'detail' parameter in terms of the returned shape, adding meaning beyond the schema's raw enum/default definitions.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description uses the specific verb 'List' with a clear resource, 'play pages', and states the optional filters (attachment and documentType). It doesn't explicitly differentiate itself from sibling tools like play_list_user_pages or play_get_page, so while the purpose is clear, the sibling distinction is left implicit.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description gives concrete usage guidance with a worked example for session recaps ('pass refType: session, refId: <sessionId>, documentType: player-recap'), which tells the agent when this filter combination is appropriate. It doesn't explicitly state when not to use this tool versus alternatives, but the usage context is otherwise clear.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

play_list_participated_campaignsList campaigns I play inA
Read-onlyIdempotent
Inspect

List campaigns where the calling user is a player (not the DM). Each campaign's ruleset-specific material lives in its legs array — one entry per ruleset, each carrying { ruleset, active, ... }; there is no campaign-level ruleset field. Pair with play_list_my_campaigns for a complete view of the user's campaign involvement.

ParametersJSON Schema
NameRequiredDescriptionDefault

No parameters

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.5/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint=true, idempotentHint=true, and destructiveHint=false, so the safety profile is well covered. The description adds valuable behavioral context by explaining the structure of the legs array and the absence of a campaign-level ruleset field, which helps the agent anticipate response shape and interpret results correctly.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is two sentences with no filler. The core purpose is front-loaded, and the additional structural detail about the legs array earns its place by clarifying a non-obvious data shape. It is both concise and well-organized.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a zero-parameter read-only list tool with an output schema and strong annotations, the description covers everything needed: what it returns, the key structural nuance, and how it relates to the sibling tool. There is no significant missing information.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The tool has zero parameters and the schema is an empty object, so parameter semantics are trivially complete. Baseline 4 is appropriate since the description doesn't need to add parameter details and doesn't introduce any confusion.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states precisely what the tool does: it lists campaigns where the calling user is a player, explicitly excluding the DM role. It also distinguishes the tool from play_list_my_campaigns by positioning it as the player-only view, making sibling differentiation clear.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description gives clear context for when to use this tool: when you need campaigns where the user is a player, not a DM. It also names the sibling play_list_my_campaigns and recommends pairing them for a complete view, though it doesn't explicitly say when to choose one over the other beyond the player/DM distinction.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

play_list_pbem_inboxList a campaign's PBEM inboxA
Read-onlyIdempotent
Inspect

List the captured inbound emails on a play-by-email campaign. Each item carries the matched player (or null when unmatched), sender display name, sent time, subject, verbatim body, a distilled replyText (latest contribution with quoted history stripped), senderIsGamemaster (true when the sender is the campaign owner or an accepted gamemaster — the move builder boxes GM emails), and senderDisplayName (the GM-set attribution name for the matched player, empty when unset). GM-only.

ParametersJSON Schema
NameRequiredDescriptionDefault
statusNoFilter by item status. 'new' (default) is the pending pile awaiting triage; 'consumed' items are linked to a published move; 'dismissed' items were discarded by the GM.new
campaignIdYesMongo `_id` of the play campaign.

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already mark this read-only, idempotent, and non-destructive. The description adds value beyond annotations by explaining GM-only access, the null matched-player case, replyText stripping quoted history, and the senderIsGamemaster/senderDisplayName semantics.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The purpose is front-loaded in the first sentence, and the follow-up sentence packs useful return-field semantics without filler. The long parenthetical about the move builder is slightly dense, but no sentence is wasted.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a read-only listing tool, the description covers the access restriction, the status-filtered subject matter, and the meaning of the returned fields. With a full parameter schema, readOnly/idempotent annotations, and an output schema present, nothing essential is missing for an agent to call it correctly.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, with campaignId and status fully described including the enum meanings and default. The description reinforces the item-level concepts but does not add parameter-level details beyond what the schema already provides, so the baseline of 3 applies.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description opens with the specific action 'List' and a precise resource: captured inbound emails on a play-by-email campaign. It also explains what each returned item contains, leaving no ambiguity about what the tool does and how it differs from mutation siblings like play_consume_pbem_emails or play_dismiss_pbem_email.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The 'GM-only' note gives an access constraint, and the title implies the use case of reviewing a campaign's PBEM inbox. However, the free-text description never explicitly says when to choose this over related tools such as play_consume_pbem_emails or play_resolve_pbem_email; the usage guidance is implied rather than stated.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

play_list_pending_friendsList pending friend requestsA
Read-onlyIdempotent
Inspect

List friend requests directed at the calling user that have not yet been accepted or declined.

ParametersJSON Schema
NameRequiredDescriptionDefault

No parameters

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint=true, idempotentHint=true, and destructiveHint=false, covering safety. The description adds the scoping constraint (pending requests for the calling user), which is useful for selection but does not disclose additional behavioral aspects like pagination, ordering, or return format beyond what the output schema presumably covers.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is a single, tight sentence with no filler. It front-loads the verb and resource and clearly states the filtering condition, making it easy for an agent to parse quickly.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a simple read-only list operation with no parameters and an output schema present, the description is complete. It clearly defines the input scope and result semantics. Minor missing details like pagination limits could be added but are not critical given the tool's simplicity and the presence of an output schema.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The tool has zero parameters and the description correctly avoids repeating schema information. Since there are no params to explain, a baseline of 4 is appropriate; the description provides no additional parameter details because none are needed.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the verb 'List', the resource 'friend requests', and the specific scope: 'directed at the calling user that have not yet been accepted or declined.' This precisely distinguishes it from sibling tools like play_list_my_friends (which lists all friends) and accept/decline/cancel actions.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description implies usage by specifying the pending status and target user, but it does not explicitly state when to use this tool versus alternatives (e.g., play_list_my_friends, play_accept_friend_request). No when-not or alternative guidance is provided beyond the inherent scope.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

play_list_session_movesList a chapter's movesA
Read-onlyIdempotent
Inspect

List the moves grouped under one session (a play-by-email 'chapter'), in reading order with full bodies by default; detail: 'summary' trims each description to a ~240-character prose preview with a descriptionTruncated flag. Restricted moves are server-filtered to the caller's visibility. Caller must be a member of the session's campaign.

ParametersJSON Schema
NameRequiredDescriptionDefault
detailNoResponse shape. 'full' (default) returns complete bodies in reading order. 'summary' trims each move's description to a ~240-character prose preview — image URLs and [[...]] markers don't count toward the budget and the cut lands on a word boundary — and adds a `descriptionTruncated` boolean flagging whether more remains.full
sessionIdYesMongo `_id` of the chapter session.

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.5/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint, idempotentHint, and destructiveHint, so the safety profile is covered. The description adds genuinely valuable behavioral context beyond that: restricted moves are server-filtered to the caller's visibility, the summary mode truncates to a prose preview with a descriptionTruncated flag, and a campaign-membership auth requirement exists. No contradiction with annotations.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Three sentences, zero waste. The core action and default behavior are front-loaded, the summary-mode behavior is compressed into one semicolon clause (with full detail delegated to the schema), and the visibility filtering and membership requirement each earn their own sentence.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a 2-parameter, non-nested list operation with a full output schema and complete safety annotations, the description covers everything an agent needs: ordering, default vs summary modes, visibility filtering, and the caller prerequisite. Return-value shape is handled by the output schema, and pagination is not a meaningful gap given no pagination parameters exist.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so the schema already fully documents both parameters — the detail param description is exceptionally thorough (truncation budget, word-boundary cuts, flag semantics). The description restates the detail behavior only briefly and adds no new syntactic or format information, so the baseline 3 applies.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource — 'List the moves grouped under one session' — and clarifies the domain-specific term ('a play-by-email chapter'). The scope is further pinned down by 'in reading order with full bodies by default,' making it easily distinguishable from siblings like play_list_campaign_moves, play_get_move, or play_list_campaign_sessions without opening their schemas.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Provides clear context: this is the tool for listing moves within one session, with a stated prerequisite ('Caller must be a member of the session's campaign') and guidance on choosing summary vs full detail. It stops short of explicitly naming alternatives or exclusions (e.g., 'use play_get_move for a single move'), which the large sibling list would have benefited from.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

play_list_user_pagesList pages authored by a userA
Read-onlyIdempotent
Inspect

List the pages a given user has authored. Pass own user id (from whoami) to see private pages too; for another user, only public pages come back. Defaults to summary shape.

ParametersJSON Schema
NameRequiredDescriptionDefault
detailNoResponse shape. 'summary' (default) drops the markdown `description` body and trims the owner populate, keeping identification + `ref` + `documentType` + the short `summary` field. 'full' returns the populated page document including the full body.summary
userIdYesMongo `_id` of the user whose pages to list. Pass own user id (from `whoami`) to see private pages too; for another user, only public pages come back.

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.1/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already indicate read-only, idempotent, and non-destructive behavior. The description adds useful context about privacy scoping based on whose userId is passed, and notes the default summary response shape. No contradiction with annotations.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two concise sentences, with the main purpose front-loaded and the key usage nuance immediately following. Every sentence adds value and there is no filler.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a low-complexity read tool with a rich schema, an output schema, and full annotations, this description covers the essential behavior, privacy semantics, and default response shape. Nothing critical is missing for an agent to call it correctly.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100% and the description largely repeats what the schema already documents, including the privacy behavior and default summary shape. The description adds no substantial new parameter meaning beyond the schema.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states a specific verb and resource: 'List the pages a given user has authored.' This is clear and distinct from a generic page-listing tool, but it does not explicitly differentiate from sibling tools like play_list_pages.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description gives clear context: pass your own user id to see private pages, another user id to see only public pages. It does not explicitly mention alternatives or when-not-to-use the tool, but the provided usage context is practical and actionable.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

play_regenerate_pbem_addressRegenerate a campaign's inbound addressA
DestructiveIdempotent
Inspect

Mint a fresh inbound address for the campaign (leak recovery). The old address stops routing IMMEDIATELY and every player must switch to the new one — confirm with the user first. GM-only.

ParametersJSON Schema
NameRequiredDescriptionDefault
campaignIdYesMongo `_id` of the play campaign.

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.5/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

The description adds rich behavioral context beyond the annotations: the old address stops routing immediately, every player must switch, confirmation is required, and the operation is GM-only. This substantially exceeds what 'destructiveHint: true' alone conveys and gives an agent the necessary risk framing.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is two sentences, efficiently front-loading the core action and then the critical consequences. Every clause earns its place: leak recovery, immediate routing stop, player impact, user confirmation, and GM-only restriction.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a destructive, non-obvious operation, the description covers all essential context: why to call it, what will happen, who is allowed, and what prerequisite coordination is needed. With an output schema and clear parameter documentation present, nothing necessary for correct invocation is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100% and the single parameter campaignId is already well-documented as a Mongo _id. The description does not need to add parameter detail, but it also does not add anything beyond the schema, so the baseline score of 3 is appropriate.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states a specific action ('Mint a fresh inbound address for the campaign') and identifies the purpose via 'leak recovery'. It also explains the concrete consequence—old address stops routing immediately—which distinguishes this from any similar-looking play_* tools.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description gives clear context for when to use it: as leak recovery, with the explicit directives to confirm with the user first and only for GMs. It does not name alternatives or exclusions, but none of the siblings appear to be a direct substitute, so the guidance is sufficient.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

play_remove_campaign_itemRemove an item from a campaign's allowlistA
DestructiveIdempotent
Inspect

Remove a vault item from a campaign's allowlist. Removal targets the leg matching the ITEM's own ruleset; the optional ruleset param only confirms that leg (mismatch answers 400), never retargets. Caller must have 'contribute'.

ParametersJSON Schema
NameRequiredDescriptionDefault
itemIdYesVault document id (`itemId`) to remove. Required.
rulesetNoOptional confirmation of the target leg's ruleset. The entity always lands on the leg matching its OWN ruleset — this param never retargets; when present, play verifies it matches that leg and answers 400 on a mismatch. Omit unless you want the placement double-checked.
campaignIdYesCampaign id.

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.1/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Adds real context beyond the annotations: the removal always targets the leg matching the item's own ruleset, the `ruleset` param never retargets and yields a 400 on mismatch, and the caller needs 'contribute'. Destructive/idempotent hints are already covered by annotations, and the description leaves unstated what happens if the item is not on the allowlist.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Three tight sentences that front-load the action, then the non-obvious targeting rule, then the auth requirement. Dense but every clause carries information; only minor redundancy with the schema on the ruleset point.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With an output schema present, rich annotations, and full schema descriptions, the description only needs to supply behavioral nuance — and it covers permission requirements and the surprising ruleset-leg targeting rule. Little an agent needs is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100% and the schema's `ruleset` text already carries the confirmation/400 semantics, so the description largely duplicates it. Baseline 3 is appropriate; no extra syntax or format detail is added.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb ('Remove') and resource ('a vault item from a campaign's allowlist'), which cleanly separates it from play_add_campaign_item and the spell/rule removal siblings. The scope is unambiguous without opening the schema.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explains when to use the optional `ruleset` param ('omit unless you want the placement double-checked') and states the permission prerequisite ('Caller must have contribute'). It does not name a sibling alternative or exclusion case, so it falls short of a 5.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

play_remove_campaign_playerRemove a player from a campaignA
DestructiveIdempotent
Inspect

Remove a player from a campaign. Caller must have 'contribute'. The campaign owner cannot be removed. playerId is the player-record id returned by play_list_campaign_players (the embedded player doc id, NOT the user's id).

ParametersJSON Schema
NameRequiredDescriptionDefault
playerIdYesEmbedded player document id from play_list_campaign_players.
campaignIdYesCampaign id.

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.7/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already convey destructive and idempotent behavior. The description adds non-obvious behavioral constraints: the permission requirement, the owner cannot be removed, and the critical clarification that playerId is the embedded player doc id, not the user's id. There is no contradiction with annotations.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Three concise sentences, front-loaded with the action, with each subsequent sentence adding a necessary constraint or disambiguation. There is no filler or repeated schema content.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a two-parameter tool with an output schema and annotations already covering safety and idempotency, the description supplies the permission requirement, ownership constraint, and ID provenance. An agent has the information needed to select and invoke it correctly.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, so the baseline is 3. The description adds extra meaning for playerId by stressing that it is returned by play_list_campaign_players and is NOT the user's id, which reduces a likely mistake. campaignId is simple and already adequately described in the schema.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description uses a specific verb ('Remove') with a clearly bounded resource ('a player from a campaign'). This distinguishes it from sibling removal tools targeting items, rules, or spells.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description provides clear context: a required permission ('contribute'), an exclusion ('campaign owner cannot be removed'), and a pointer to play_list_campaign_players as the source of the playerId. It does not explicitly name alternative tools or provide when-not-to-use guidance, so it stops short of a 5.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

play_remove_campaign_ruleRemove a rule from a campaign's allowlistA
DestructiveIdempotent
Inspect

Remove a vault rule from a campaign's allowlist. Removal targets the leg matching the RULE's own ruleset; the optional ruleset param only confirms that leg (mismatch answers 400), never retargets. Caller must have 'contribute'.

ParametersJSON Schema
NameRequiredDescriptionDefault
ruleIdYesVault document id (`ruleId`) to remove. Required.
rulesetNoOptional confirmation of the target leg's ruleset. The entity always lands on the leg matching its OWN ruleset — this param never retargets; when present, play verifies it matches that leg and answers 400 on a mismatch. Omit unless you want the placement double-checked.
campaignIdYesCampaign id.

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.1/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already flag destructive/idempotent/open-world behavior, and the description adds genuine operational detail: removal targets the leg matching the rule's own ruleset, and a ruleset mismatch returns 400. It stops short of describing side effects on dependent campaign state.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Three tight sentences, front-loaded with the action, followed by the targeting rule and the auth requirement. The middle sentence is dense but every clause carries information.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

An output schema exists so return values need not be explained, and the description covers the targeting nuance and auth requirement. Minor gaps remain around failure modes other than the mismatched-ruleset 400.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100% and the schema description already explains the ruleset-confirmation semantics, so the description is largely restating it. The baseline of 3 is appropriate here.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource ('Remove a vault rule from a campaign's allowlist'), which cleanly separates it from siblings like play_add_campaign_rule, play_remove_campaign_item, and play_remove_campaign_spell.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Gives a precondition ('Caller must have contribute') and clearly frames the optional ruleset param as a confirmation rather than a selector, but never explicitly names an alternative tool or a when-not-to-use condition.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

play_remove_campaign_spellRemove a spell from a campaign's allowlistA
DestructiveIdempotent
Inspect

Remove a vault spell from a campaign's allowlist. Removal targets the leg matching the SPELL's own ruleset; the optional ruleset param only confirms that leg (mismatch answers 400), never retargets. Caller must have 'contribute'.

ParametersJSON Schema
NameRequiredDescriptionDefault
rulesetNoOptional confirmation of the target leg's ruleset. The entity always lands on the leg matching its OWN ruleset — this param never retargets; when present, play verifies it matches that leg and answers 400 on a mismatch. Omit unless you want the placement double-checked.
spellIdYesVault document id (`spellId`) to remove. Required.
campaignIdYesCampaign id.

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.1/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare destructive=true, idempotent=true, and openWorld=true, so safety is covered. The description adds real value beyond that: the required 'contribute' permission and the leg-matching/400-on-mismatch behavior, which an agent needs to avoid errors.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Three tight sentences, front-loaded with the action and followed by the targeting nuance and permission requirement. The ruleset explanation is somewhat dense and partially echoes the schema, but every sentence carries operational weight.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With an output schema present, return values need not be described, and the permission, targeting, and error behavior are all covered. Complete enough for a mutation tool whose annotations already carry the safety profile, though it omits any note on side effects on unaffected legs.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so the schema already documents all three params including the non-retargeting ruleset semantics. The description reinforces the ruleset behavior but adds no syntax or format detail beyond the schema, matching the baseline for full coverage.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb (Remove) and resource (a vault spell from a campaign's allowlist), which clearly distinguishes it from vault_delete_spell (deletes the spell itself) and play_add_campaign_spell (the inverse operation). An agent can identify it without opening the schema.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Gives a clear prerequisite ('Caller must have contribute') and clarifies the ruleset param's role, which is the main usage pitfall. It does not name sibling alternatives (e.g., vault_delete_spell for permanent deletion) or exclusions explicitly, so it falls short of a 5.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

play_remove_friendRemove a friendA
DestructiveIdempotent
Inspect

Remove an existing friend connection. Pass friendId from play_list_my_friends. Destructive on the social graph; both sides lose the connection.

ParametersJSON Schema
NameRequiredDescriptionDefault
friendIdYes`_id` of the friend record on the calling user's friends list. NOT the other user's id. Use play_list_pending_friends (for accept/decline) or play_list_my_friends (for remove) to obtain it.

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.3/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already flag this as destructive and not read-only. The description adds meaningful behavioral context beyond those flags: 'Destructive on the social graph; both sides lose the connection,' which tells the agent the exact blast radius and impact. It does not address auth or reversibility, but the annotations carry the core safety signal.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is three short sentences with no filler. It front-loads the action, then supplies the parameter source, then the destructive consequence. Every sentence earns its place.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a single-parameter, destructive tool with an output schema and rich parameter documentation, the description is complete. It covers what the tool does, where the parameter comes from, and the social-graph consequence, leaving no important selection or invocation gap.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100% and the parameter description already explains that `friendId` is the friend record `_id` on the calling user's friends list, NOT the other user's id, and how to obtain it. The description repeats the provenance ('Pass `friendId` from play_list_my_friends') but adds no new parameter semantics, so the baseline of 3 applies.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description opens with a specific verb and resource: 'Remove an existing friend connection.' It distinguishes this from pending-request operations by emphasizing 'existing friend connection,' which separates it from tools like play_cancel_friend_request, play_accept_friend_request, and play_decline_friend_request.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description gives clear operational guidance by telling the agent to pass `friendId` from play_list_my_friends, which indicates the correct source and workflow. It does not explicitly name alternative tools for accept/decline/cancel, but the 'existing friend connection' framing implies the boundary; the schema's parameter description further clarifies that play_list_pending_friends is for accept/decline.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

play_resolve_pbem_emailAssign an unmatched email to a playerA
Idempotent
Inspect

Resolve an unmatched inbox email to an accepted campaign member. Pass remember: true to auto-match future emails from the same sender address (stored as an HMAC key, never the address). GM-only.

ParametersJSON Schema
NameRequiredDescriptionDefault
itemIdYesMongo `_id` of the inbox item.
playerIdYesUser `_id` of the accepted campaign member this email's sender is.
rememberNoWhen true, future emails from the same sender address auto-match this player (stored as an HMAC key, never the address).

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.4/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Beyond the annotations, it discloses GM-only authorization, the persistent side effect of auto-matching future emails when remember is true, and the privacy behavior of storing only an HMAC key, never the address. This adds meaningful behavioral context without contradicting the annotations.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two tight sentences with no filler. The core action is front-loaded, followed by the optional remember behavior and the permission constraint, each earning its place.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

The description is largely complete for a tool with a rich output schema and fully documented parameters. The only notable gap is the absence of explicit routing guidance against related PBEM email tools, such as dismissing instead of resolving.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The input schema already documents all three parameters with 100% coverage, including the HMAC-key note on remember. The description restates some of this information but does not substantially expand on the schema's parameter meanings.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description uses a specific verb and resource: 'Resolve an unmatched inbox email to an accepted campaign member.' It clearly separates this from siblings like play_dismiss_pbem_email and play_consume_pbem_emails by targeting unmatched emails and assigning them to a player.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It gives clear context about when the tool is appropriate: an unmatched inbox email should be resolved to an accepted campaign member, and GM-only restricts who may call it. It does not explicitly contrast with dismissal or bulk-consumption siblings, so it lacks explicit when-not guidance.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

play_respond_to_campaign_inviteAccept or decline a campaign inviteAInspect

Respond to a pending campaign invite directed at the calling user. The campaign id is the campaign the invite belongs to; accept decides yes/no.

ParametersJSON Schema
NameRequiredDescriptionDefault
acceptYestrue to accept the invite; false to decline.
campaignIdYesCampaign id.

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.1/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already communicate that this is a mutating, non-idempotent operation, so the description does not need to restate that. It adds useful scope context ('pending', 'directed at the calling user'), but it does not disclose what happens after responding, such as whether the invite is consumed or what side effects accepting has.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is two short, front-loaded sentences with no filler. The action and scope come first, then the parameter clarifications, making it easy to parse quickly.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a simple two-parameter action with full schema coverage, an output schema, and relevant annotations, the description is complete enough. It identifies the target resource, the caller-scope constraint, and the meaning of the decision parameter.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, and both parameters already have clear descriptions ('Campaign id.' and 'true to accept the invite; false to decline.'). The prose adds only minor natural-language clarification that campaignId is the campaign the invite belongs to and that accept decides yes/no.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states a specific verb and resource: 'Respond to a pending campaign invite directed at the calling user.' It clearly distinguishes this from sibling friend-request tools like play_accept_friend_request and play_decline_friend_request by specifying the campaign-invite scope.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The phrase 'pending campaign invite directed at the calling user' gives clear conditions for when to use the tool. It does not explicitly name alternatives or exclusions, but the context is sufficient to route an agent to the correct tool without opening other schemas.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

play_send_friend_requestSend a friend requestA
Idempotent
Inspect

Send a friend request to another user. Pass targetUserId (the recipient's User _id) — use play_find_friend to look them up first.

ParametersJSON Schema
NameRequiredDescriptionDefault
targetUserIdYesMongo `_id` of the user to send the friend request to. Use play_find_friend to locate it.

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.1/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

The annotations already signal a non-read-only, non-destructive, idempotent state change, and the description does not contradict them. It adds little beyond the schema (the targetUserId format and lookup step), but for this simple action the task-facing behavior is adequately implied. It could have noted that success creates a pending request that requires acceptance, but this is a minor gap.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

One compact, front-loaded sentence with no filler; the action, parameter, and lookup prerequisite all appear in the first clause.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With a single required parameter, full schema coverage, an output schema, and annotations covering safety semantics, the description plus structured data leave no practical gap. The explicit lookup-first instruction completes the workflow.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100% and the schema already documents targetUserId as the recipient's Mongo _id and tells the agent to use play_find_friend. The description restates this, adding a slightly clearer sequencing cue ('look them up first') but no new parameter meaning.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description opens with the specific action 'Send a friend request' and clearly identifies the resource ('another user'). It also names the target identifier and points to play_find_friend, which separates it from sibling request-management tools like play_accept_friend_request or play_cancel_friend_request.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It gives an explicit precondition: look up the recipient with play_find_friend before sending. It does not enumerate exclusions such as 'do not use for accepting/declining/cancelling', but the verb and the named lookup sibling make the context clear.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

play_set_campaign_leg_activeActivate or deactivate a campaign legA
Idempotent
Inspect

Toggle a campaign leg's active flag by ruleset. Deactivating hides the leg from normal UI (the campaign stops appearing to viewers whose active ruleset matches it) but never deletes it — all of its content and attachments survive and reactivating restores them. Play refuses to deactivate the last active leg (400). Caller must be the campaign owner or an accepted gamemaster; ordinary players get 403.

ParametersJSON Schema
NameRequiredDescriptionDefault
activeYestrue to activate the leg; false to deactivate it (hidden from normal UI, never deleted). Play refuses to deactivate the last active leg (400).
rulesetNoRuleset of the leg to toggle. Required.
campaignIdYesCampaign id.

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.3/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Goes well beyond the annotations: it explains that deactivation hides but never deletes, that content and attachments survive and reactivation restores them, that the last active leg is refused with 400, and that only the owner or a gamemaster may call it (403 for ordinary players). This is exactly the kind of auth, error, and side-effect detail annotations cannot express.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Three tightly packed sentences, front-loaded with the core action, then consequences, then error/auth conditions. No filler; each sentence carries distinct, load-bearing information.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With an output schema present, return values need not be described, and the description already covers side effects, reversibility, error codes, and permission requirements. Nothing material for correct invocation is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so the schema already documents all three parameters, and the description adds only a general 'by ruleset' reference. Baseline 3 is appropriate when the schema carries parameter meaning.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb (toggle) and resource (a campaign leg's `active` flag) and scopes it 'by ruleset'. An agent can immediately distinguish this from additive siblings like play_add_campaign_leg or general updates like play_update_campaign.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description conveys the effect and constraints of toggling, which implies when it applies, but never explicitly routes the agent between this and alternatives (e.g., play_update_campaign or play_add_campaign_leg). Usage context is present but not framed as when-to-use/when-not.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

play_set_pbem_display_nameSet a player's PBEM attribution nameA
Idempotent
Inspect

Set the name a campaign member's emails are attributed to when collated into a move (e.g. the character they play). Applies to all of that player's emails; blank clears it back to their Embers name. GM-only.

ParametersJSON Schema
NameRequiredDescriptionDefault
playerIdYesUser `_id` of the accepted campaign member.
campaignIdYesMongo `_id` of the play campaign.
displayNameYesName this player's emails are attributed to when collated into a move (e.g. their character). Pass an empty string to clear it back to the player's Embers name.

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.2/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already indicate idempotentHint=true and destructiveHint=false, so the description doesn't need to restate those. It adds useful behavioral context: the setting applies globally to all of the player's emails, and blank clears it. It doesn't mention permissions (GM-only) or side effects beyond the attribution, but the core behavior is transparent.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is two sentences, front-loads the main action, and includes the key edge case (blank clears) without any fluff. Every sentence earns its place.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the output schema exists and annotations cover idempotency and non-destructiveness, the description is nearly complete. It could mention GM-only permission or that this is a per-campaign setting, but the core behavior and parameter semantics are fully covered. A small gap remains around permissions and scope.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so the schema already documents all three parameters thoroughly. The description adds the 'applies to all of that player's emails' context and the blank-clears behavior, which complements the displayName parameter description. However, it doesn't add much beyond what the schema already says, so baseline 3 is appropriate.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the action ('Set the name a campaign member's emails are attributed to when collated into a move'), the resource (player/campaign), and the effect (applies to all of that player's emails; blank clears it). It distinguishes itself from siblings like play_create_move or play_update_move by focusing on email attribution display name.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description explains the context: it applies to all of a player's emails and that passing an empty string clears it back to the player's Embers name. It doesn't explicitly name alternative tools or when not to use it, but the context is clear enough for an agent to select it for setting attribution names.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

play_update_campaignUpdate a play campaignA
Idempotent
Inspect

PUT updates to one campaign by id. Caller must have campaign 'contribute' permission (DM or assigned co-DM). Only supplied fields are sent; play decides how to merge. legs is NOT writable here (it is stripped): add a leg with play_add_campaign_leg, toggle one with play_set_campaign_leg_active, and change a leg's contents with the add/remove rule/item/spell/character tools. REQUIRES baseUpdatedAt: copy updatedAt from a fresh play_get_campaign read; a stale or fabricated value is rejected with OUT_OF_SYNC and nothing is written.

ParametersJSON Schema
NameRequiredDescriptionDefault
idYesMongo `_id` of the campaign.
nameNoCampaign name.
imageNoImage URL. Stored as a plain string.
activeNo
publicNoWhether non-members can see the campaign.
summaryNoShort campaign summary. Max 150 characters.
sessionsNo
descriptionNoFull campaign description. Markdown supported.
hideSectionsNo
xCardEnabledNo
baseUpdatedAtYesREQUIRED proof that you are working from the latest version: copy the `updatedAt` value verbatim from a FRESH read of this exact record (use the matching get tool first). Values from memory, from an earlier conversation, or guessed timestamps are rejected with OUT_OF_SYNC and nothing is written. After a successful update, the response carries the new `updatedAt` — use that for any follow-up write.

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.8/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

The description goes well beyond the annotations: it discloses the permission requirement, the partial-merge semantics ('Only supplied fields are sent; play decides how to merge'), the fact that `legs` is silently stripped, and the optimistic-concurrency failure mode (OUT_OF_SYNC, nothing written). This adds substantial context that annotations alone do not provide.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is dense and well-structured, front-loading the core action before moving to permissions, merge behavior, exclusions, and concurrency. It is slightly longer than strictly necessary because it partially restates the `baseUpdatedAt` guidance already present in the schema, but every sentence carries useful information.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a mutating tool with 11 parameters and nested objects, the description covers the critical operational aspects: authorization, precondition (fresh read), merge semantics, unsupported field routing, and error behavior. The response shape is covered by the existing output schema, so that omission is acceptable.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 64%, so the description does need to add some meaning, and it does: the partial-update contract clarifies how optional fields behave, and the `baseUpdatedAt` requirement is reinforced with a concrete workflow. However, most individual field semantics are already well described in the schema, so the description's marginal per-parameter value is moderate.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description opens with a clear verb and resource ('PUT updates to one campaign by id'), making the operation unmistakable. It further distinguishes itself from related tools by explicitly stating that `legs` is not writable here and directing to the appropriate sibling tools. This is specific enough to prevent confusion with play_update_session, play_update_page, or the leg tools.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description gives explicit when-to-use guidance: update a campaign by id, with the required permission context and a fresh `baseUpdatedAt` from play_get_campaign. It also names the alternatives for leg-related operations and clearly excludes them from this tool's scope. This is exactly the kind of routing guidance an agent needs.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

play_update_character_noteUpdate a character note (DM or player)A
Idempotent
Inspect

Update the DM-side or player-side note attached to a play character. PUT semantics — description replaces the current body. Authorization runs through the character's campaign 'contribute' permission. Triggers a notification (to the character owner if a GM updated, to GMs if a player updated). REQUIRES baseUpdatedAt: copy updatedAt from a fresh play_get_character_note read of the same note; a stale or fabricated value is rejected with OUT_OF_SYNC and nothing is written.

ParametersJSON Schema
NameRequiredDescriptionDefault
nameNoOptional new name for the note.
characterIdYesMongo `_id` of the play character (NOT the vault character id).
descriptionYesNote body markdown. PUT semantics: replaces the existing body.
documentTypeYesWhich note to update: 'dm-notes' or 'player-notes'.
baseUpdatedAtYesREQUIRED proof that you are working from the latest version: copy the `updatedAt` value verbatim from a FRESH read of this exact record (use the matching get tool first). Values from memory, from an earlier conversation, or guessed timestamps are rejected with OUT_OF_SYNC and nothing is written. After a successful update, the response carries the new `updatedAt` — use that for any follow-up write.

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.7/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Despite annotations covering readOnlyHint=false, idempotentHint=true, and destructiveHint=false, the description adds valuable behavioral context: the authorization path, the notification triggers, the concurrency check (OUT_OF_SYNC), and the guarantee that nothing is written on failure. These go beyond the annotations and are critical for correct invocation.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is efficient: every sentence contributes necessary information. It front-loads the main action, then covers semantics, auth, notification, and the critical concurrency requirement. No filler or redundancy; the length is justified by the complexity of the operation.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a write operation with concurrency controls and side effects, the description is complete. It covers the operation, authorization, notification behavior, the required prerequisite, failure mode, and the response containing the new updatedAt. With an output schema present, nothing essential is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The input schema already provides detailed descriptions for all five parameters, with 100% coverage. The tool description adds the PUT semantics context and reiterates the baseUpdatedAt requirement, but these are also present in the schema. Thus the description adds marginal value beyond the schema, matching the baseline of 3.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the verb (update), the resource (character note), and distinguishes between DM-side and player-side notes. It also mentions PUT semantics, which clarifies the replacement behavior. This is specific enough to differentiate from sibling tools like play_get_character_note or vault_update_character.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description explicitly instructs the agent to copy baseUpdatedAt from a fresh play_get_character_note read, states the rejection behavior for stale values, and clarifies the authorization requirement via the campaign's 'contribute' permission. It also notes the notification side effect. This gives clear when-to-use guidance and a mandatory prerequisite.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

play_update_moveUpdate a moveA
Idempotent
Inspect

Update a move by id: name, description, number (game label), date, order (shelf position), sessionId (chapter; null detaches), parentId (child scene; null detaches; setting it clears the chapter), or playerIds (visibility; [] reopens to everyone). Only supplied fields are sent. GM-only. REQUIRES baseUpdatedAt: copy updatedAt from a fresh play_get_move read; a stale or fabricated value is rejected with OUT_OF_SYNC and nothing is written.

ParametersJSON Schema
NameRequiredDescriptionDefault
idYesMongo `_id` of the move to update.
dateNoMove date in `dd/mm/yy` format. Defaults to today on create. Play parses this server-side on both create and update.
nameNoMove name / title (e.g. 'Move 185', 'Interlude 12'). Defaults to 'Move <number>' when omitted on create.
orderNoShelf position within the campaign (the feed's only sort key; GM drag-reordering rewrites it). Positive integer.
numberNoGame label number. Non-unique (parallel scenes share one). Defaults to the campaign's high-water + 1 on create. Display position is `order`, not this.
parentIdNoParent move, making this a child scene (split party). Same campaign only, one level deep (a child cannot be a parent; a move with children cannot become a child). Children render on the parent's page, stay out of the feed and chapter lists, and cannot carry a sessionId. Pass null to detach back into the feed.
playerIdsNoVisibility restriction: user ids from the campaign's player roster. Empty/omitted = visible to every campaign participant. When set, the move is invisible to players not listed (dropped from lists, 404 on read); the GM always sees it. Pass [] on update to reopen the move to everyone.
sessionIdNoChapter session to group this move under. Must belong to the same campaign. Pass null to detach the move back to the unchaptered feed.
descriptionNoThe collated round: GM narration, player contributions, rolls. Markdown supported.
baseUpdatedAtYesREQUIRED proof that you are working from the latest version: copy the `updatedAt` value verbatim from a FRESH read of this exact record (use the matching get tool first). Values from memory, from an earlier conversation, or guessed timestamps are rejected with OUT_OF_SYNC and nothing is written. After a successful update, the response carries the new `updatedAt` — use that for any follow-up write.

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.8/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations declare readOnlyHint=false, idempotentHint=true, destructiveHint=false. The description adds substantial context: partial-update semantics ('Only supplied fields are sent'), optimistic concurrency requirement, GM-only access, and side effects of null values like 'null detaches' and 'setting it clears the chapter'. This exceeds what annotations convey.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is one dense but well-organized paragraph that front-loads the supported fields and places the critical concurrency warning prominently. It is compact for 10 parameters. A line break before the baseUpdatedAt warning would improve scannability, but every sentence is necessary and non-redundant.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a complex 10-parameter mutation tool, the description covers update semantics, required precondition (fresh read), failure mode, GM restriction, and field-level dependencies. The output schema exists, so return-value details need not be spelled out. Highly complete.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema covers 100% of parameters with rich descriptions, so the description need not repeat them. The description adds semantic gloss: 'null detaches', '[] reopens to everyone', 'sessionId (chapter; null detaches)', and the critical baseUpdatedAt provenance rule. Given the schema already documents each parameter, a 4 is appropriate.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states a specific verb and resource: 'Update a move by id', then enumerates all mutable fields and their semantics. It distinguishes from siblings like play_create_move and play_delete_move by being explicitly an update. The title and description align, and the resource (move) is clearly differentiated from page/session/campaign tools.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description provides strong usage guidance: it lists only-supplied-fields-are-sent behavior, states GM-only requirement, and explicitly instructs the agent to copy baseUpdatedAt from a fresh play_get_move read. It warns against stale or fabricated values and explains the OUT_OF_SYNC failure mode. This gives clear when-to-use context against sibling read tools.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

play_update_pageUpdate a pageA
Idempotent
Inspect

Update a page by id. PUT semantics — supplied fields replace their current values. To append to a recap body, fetch first via play_get_page, concatenate, and send back. Caller must have page 'contribute' permission. REQUIRES baseUpdatedAt: copy updatedAt from a fresh play_get_page read; a stale or fabricated value is rejected with OUT_OF_SYNC and nothing is written — writing from memory of an earlier read is not possible.

ParametersJSON Schema
NameRequiredDescriptionDefault
idYesMongo `_id` of the page to update.
refNoWhat the page is attached to. Required for character notes; optional for free-form pages. Allowed on update too (Mongoose has no immutability constraint), though re-anchoring a page is unusual.
linkNoURL-safe slug. Lowercase letters, numbers, and hyphens only.
nameNoPage name / title.
activeNo
publicNo
summaryNoShort page summary. Max 255 characters.
keywordsNoComma-separated keyword string.
promptIdNoMongo `_id` reference (24-character hex string).
descriptionNoMarkdown body.
documentTypeNoWhat kind of page this is. Defaults to 'generic'. Use 'player-recap' for a session recap.
baseUpdatedAtYesREQUIRED proof that you are working from the latest version: copy the `updatedAt` value verbatim from a FRESH read of this exact record (use the matching get tool first). Values from memory, from an earlier conversation, or guessed timestamps are rejected with OUT_OF_SYNC and nothing is written. After a successful update, the response carries the new `updatedAt` — use that for any follow-up write.

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.5/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

The description goes well beyond the annotations by disclosing PUT semantics (supplied fields replace current values), the required fresh baseUpdatedAt with OUT_OF_SYNC rejection and no partial write, the append workaround, and the permission requirement. It contradicts no annotation; idempotentHint is consistent with the atomic no-write behavior.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loaded with the core purpose, then progressively adds behavioral detail. The paragraph is a little long but every sentence earns its place, covering semantics, a workaround, a permission, and a required precondition. Some redundancy with the baseUpdatedAt schema description exists, but the importance justifies it.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a tool with 12 parameters, nested objects, and an output schema, the description covers the main complexity: partial update semantics, optimistic concurrency, append pattern, and permission. It relies on the schema for field-level details, which is appropriate given the 83% coverage. It could mention the unusualness of re-anchoring ref, but the schema already notes that.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Although schema coverage is 83%, the description adds critical parameter-level behavior: it explains that supplied fields replace current values (clarifying the semantics of every field) and details the baseUpdatedAt requirement and the append workaround. The schema already describes each field, but the description adds workflow context that the schema cannot.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States the exact action ('Update a page by id') with a specific verb, resource, and identifier. The PUT semantics line further distinguishes it from create/delete and from other update_* siblings. The name itself already implies the resource, and the description reinforces it.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Provides a concrete pattern for appending to a recap body (fetch via play_get_page, concatenate, send back), which distinguishes update from append scenarios. It also states the required 'contribute' permission as a prerequisite. However, it does not explicitly contrast against play_create_page or other update tools, which would make the when-to-use guidance complete.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

play_update_sessionUpdate a sessionA
Idempotent
Inspect

Update a session by id. Use this to append session notes, change the date, rename, or tag the session with the Imagine adventure it belongs to (imagineAdventureId — valid ids come from the campaign's imagineAdventures list on play_get_campaign; null untags). Only the fields you supply are sent. Caller must have session 'contribute' permission. REQUIRES baseUpdatedAt: copy updatedAt from a fresh play_get_session read; a stale or fabricated value is rejected with OUT_OF_SYNC and nothing is written.

ParametersJSON Schema
NameRequiredDescriptionDefault
idYesMongo `_id` of the session to update.
dateNoSession date in `dd/mm/yy` format.
nameNoSession name / title.
imageNo
statusNo
dateDayNo
summaryNoShort session summary. Max 150 characters.
dateYearNo
dateMonthNo
battlemapsNo
charactersNo
descriptionNoSession body / notes / recap. Markdown supported.
baseUpdatedAtYesREQUIRED proof that you are working from the latest version: copy the `updatedAt` value verbatim from a FRESH read of this exact record (use the matching get tool first). Values from memory, from an earlier conversation, or guessed timestamps are rejected with OUT_OF_SYNC and nothing is written. After a successful update, the response carries the new `updatedAt` — use that for any follow-up write.
sessionImagesNo
imagineAdventureIdNoImagine adventure this session is part of. Must be one of the ids in the campaign's `imagineAdventures` list (see play_get_campaign); adventures are linked to the campaign with imagine_link_adventure_to_campaign. Pass null to untag the session. Omit to leave unchanged.

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.4/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Beyond annotations, it explains optimistic concurrency via baseUpdatedAt, the OUT_OF_SYNC failure mode with nothing written, partial-update behavior, and the required 'contribute' permission. This is exactly the behavioral context an agent needs and goes far beyond the readOnly/destructive/idempotent hints.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loaded with 'Update a session by id'; each sentence carries a distinct operational fact: what can change, partial updates, permission, and concurrency requirement. There is no filler or redundant preamble.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a complex 15-parameter mutation with an output schema, the description plus schema cover required auth, concurrency, and core fields, and the output schema covers return values. Ambiguity remains around interaction of date vs dateDay/dateMonth/dateYear and optional image/visibility fields, but not enough to impair safe invocation.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is only 47%, so the description must carry extra weight. It adds meaning for baseUpdatedAt and imagineAdventureId and clarifies partial-update behavior, but leaves date parts, image, battlemaps, sessionImages, and status semantics to schema/enum names. It covers the highest-risk parameters but does not fully compensate for the schema gap.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States precisely that it updates a session by id and enumerates representative uses (append notes, change date, rename, tag with adventure). This distinguishes it from other play_* update tools and from get/create/delete session siblings.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

'Use this to ...' gives concrete cases, and it explicitly names play_get_session as a required precursor for a fresh baseUpdatedAt. It does not enumerate exclusions such as when to prefer play_update_campaign or page updates, so it misses full when-not guidance.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

reply_to_submissionReply on one of my submissionsAInspect

Post a reply on one of the calling user's submissions, for example to answer a clarification question from Embers. Pass submissionId and text; optional attachments are ids from upload_submission_screenshot. The original report cannot be edited, and a closed submission takes no replies.

ParametersJSON Schema
NameRequiredDescriptionDefault
textNoThe reply. Optional only when attachments are provided.
attachmentsNoUpload ids from upload_submission_screenshot to attach. Optional, up to ten.
submissionIdYesMongo `_id` of one of the caller's submissions.

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.3/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Beyond the annotations (which only say the tool is not read-only, not idempotent, not destructive), the description discloses useful behavioral constraints: replies only work on the caller's submissions, the original report cannot be edited, and closed submissions reject replies. This gives the agent realistic expectations about side effects and failure conditions.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is short and front-loaded: the core action appears in the first sentence, followed by parameter guidance and constraints in the next two sentences. Every sentence adds value, with no fluff or repetition of the title.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a three-parameter mutation tool with a full schema and an output schema present, the description covers the essential context: what the tool does, who can use it, what parameters matter, how attachments relate to another tool, and the key edge case (closed submissions). Nothing critical is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, and each parameter already has a meaningful description in the schema. The tool description adds a little context by tying attachments to upload_submission_screenshot and emphasizing the text/attachment pairing, but does not significantly go beyond what the schema already documents. Baseline 3 is appropriate.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states a specific verb ('Post a reply') and resource ('one of the calling user's submissions'), and includes a concrete motivating example ('answer a clarification question from Embers'). This clearly distinguishes it from sibling tools like create_submission or get_submission.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description gives clear usage context: reply to a submission, optionally attach screenshots, and notes that a closed submission takes no replies. It also clarifies a limitation ('The original report cannot be edited'). It does not explicitly name alternative tools for when to use something else, but the guidance is sufficient for the primary workflow.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

upload_submission_screenshotUpload a screenshot for a submissionAInspect

Upload one screenshot to attach to a bug report, request, or reply. Pass mimeType and the base64 data. Returns { id, url }; pass the id in attachments on create_submission or reply_to_submission.

ParametersJSON Schema
NameRequiredDescriptionDefault
dataYesThe image bytes, base64-encoded (no data: prefix). Up to 8 MB decoded.
mimeTypeYesImage type of the screenshot.

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.1/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations are all false and don't convey substantial safety or side-effect information. The description adds the useful fact that the tool returns `{ id, url }` and that the id is used later, but it doesn't disclose idempotency, storage, or auth considerations beyond the schema's size limit.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two sentences: the first states the tool's purpose, the second covers required parameters and the return/usage contract. It is front-loaded and free of filler.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a two-parameter upload tool with complete schema documentation, an output schema, and a clear workflow, the description covers everything needed to call it correctly and integrate the result with submission creation.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Input schema coverage is 100%, with `data` and `mimeType` already documented including base64 formatting, size, and enum values. The description only repeats the parameter names, adding no semantics beyond the schema.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific action: uploads a single screenshot to attach to a bug report, request, or reply. It also names the consumer tools (create_submission and reply_to_submission), which distinguishes it from sibling operations.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description clearly defines the workflow: upload first, then pass the returned id in `attachments` on create_submission or reply_to_submission. It does not explicitly describe when not to use it or compare with alternatives, but no direct upload sibling exists.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

vault_attach_companionAttach a companion to a characterAInspect

Attach a buddy (animal companion, hireling, follower, granted NPC, stock monster) to a Main character the user owns. The row appears in the sheet's Companions section. Mode is decided by ownership: 'owned' for a character the user already owns (its values are then edited on its own document via vault_update_character — the row is a live window, no copy is made, no character slot is used); 'link' for a character someone else owns (the source is never written; track its hit points and uses via vault_update_companion_state). The same source may be attached more than once — each row is independent. Response is { companion, companions, updatedAt }; ADOPT the returned updatedAt as the Main character's fresh stamp for any follow-up write.

ParametersJSON Schema
NameRequiredDescriptionDefault
idYesMongo `_id` of the Main character (owned by the calling user) the companion is attached to.
modeYes'owned' when the calling user owns the companion character (edits then write through to that character's own document; vault answers 403 if the user does not own it). 'link' for a character someone else owns — stock monsters, a GM's NPC — tracked via a local overlay that never writes to the source. To get a fully-editable copy of a creature the user does NOT own, vault_clone_character it first, then attach the copy with mode 'owned'.
characterIdYesMongo `_id` of the character to attach as the companion.

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.8/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations are all false, so the description carries the burden. It clearly discloses that no copy is made, no character slot is used, the source is never written in link mode, rows are independent, and that the returned updatedAt must be adopted as a fresh stamp. No contradiction with annotations.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is fairly long but every sentence carries essential information: purpose, mode behavior, side effects, and response handling. It is front-loaded with the main action and results. Minor redundancy (e.g., restating the mode in the schema) but overall efficient and well-structured.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a moderate-complexity tool with three parameters and an output schema (mentioned but not shown), the description covers the operation, side effects, cross-tool usage, and how to handle the response. Nothing an agent needs to call it correctly is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, so the schema already documents all three parameters. The description adds value by reinforcing the mode semantics (403 if not owned, cloning path) and by explaining the response's updatedAt significance. This goes beyond the schema, though it doesn't add new syntax details for id/characterId.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states a specific verb ('Attach') and resource ('buddy... to a Main character'), and clarifies the result (row in Companions section). It distinguishes from siblings by referencing vault_update_character, vault_update_companion_state, and vault_clone_character, so an agent can easily tell it apart.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It explicitly defines when to use 'owned' vs 'link' based on ownership, explains the prerequisite of cloning for non-owned creatures, and notes that the same source may be attached multiple times. This is precise and directly guides tool selection and mode.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

vault_build_monsterBuild a monsterAInspect

Create a complete monster character in one call, in a ruleset the monster builder supports (the ruleset field's list; list_rulesets gives each code's label). Replaces the vault_create_character + multiple vault_update_character pattern for monster authoring — fully typed input schema, so structured fields cannot be silently stringified. Caller passes source-text values (final AC, skill bonuses, attack bonuses); vault computes the stored base values, derives proficient / expertise / misc flags, formats spell-list markdown, creates recharge trackables, generates the challenge, legendary-intro, and alternate-form speed notes. Sets type: 'monster', settings.autoPassiveBonuses: false, and the derived core.experience automatically. The authoring guide at vault_get_authoring_guide({ rulesetCode: <the monster's ruleset>, entityType: 'monster' }) documents every field's source-text meaning and is the conventions reference for what shape to send. Returns the created character document.

ParametersJSON Schema
NameRequiredDescriptionDefault
acYesAC block. `total` is the value the sheet should display (the source-text number). Vault computes the stored base from it, the `armorWeight` given, and any shield/magic/misc bonuses, per the guide Rule 1.
crYesChallenge Rating as a number, a fraction as its decimal (e.g. 0.125 for CR 1/8); vault answers an error for a value that is not a challenge rating. Vault looks up XP reward + level-equivalent XP + proficiency bonus.
hpYesMaximum hit points.
gearNoGear listed on the stat block, source text. Each becomes an items[] entry with `equipped: false` (monsters don't use equip slots) per Rule 19. Server-side template fill adds the currency items separately.
nameYesDisplay name. Required.
sizeYesSize text, source-exact: a single value or the variable form ('X or Y') per the guide Rule 18. Stored verbatim in `core.size`.
savesNoSaving throw bonuses for the proficient ones only. Vault derives `attributes[].proficient = true` and a `misc` adjustment so the sheet total lands on the source bonus.
speedYesSpeed block, in feet. `walk` is the base walking speed; the other modes become rules[] entries with the listed range. `alternateForm` carries a stat block's parenthetical alternate-form speed text, source-exact, per the guide Rule 5; lands in notes[].
sensesNoThe stat block's senses other than the passive one the sheet derives, each as `name` and `detail` (the source text after the name). Each becomes a rules[] entry. The monster authoring guide covers which senses to author.
skillsNoSkill bonuses for proficient / expertise skills only. Vault derives the proficient + expertise flags + misc so the sheet total matches the source bonus per the guide Rule 6.
traitsNoTrait entries, source text. Use `summary` for a parenthetical usage limit per the guide Rule 14, and `detail` for a short qualifier per Rule 17; senses go under `senses`.
actionsNoAction entries. `type` per the guide Rule 3. For attacks, pass `attackBonus` + `attackAttribute` + `damageDice` + `damageType` + `damageAttribute`; vault back-derives `attack.misc`. The guide Rule 3 gives `attackAttribute` for a spell attack. `recharge` takes the source's recharge text and creates a matching trackables[] checkbox the sheet renders as a cooldown; the guide gives the form.
rulesetNoA ruleset the monster builder supports. The authoring guide and the conversion math are ruleset-specific; other rulesets will land via their own build tools.
abilitiesYesAbility scores as numbers, one per ability score key. Vault computes modifiers, attack/damage/save/skill/initiative derivations.
alignmentYesAlignment text, source-exact.
languagesNoLanguages text, source-exact. Stored in `core.languages`.
immunitiesNoCombined immunities row, source-exact, damage and condition entries as the source writes them. Use this when the source has one combined immunities row.
hitDiceSizeNoHit-die size from the stat block. Omitted, the app chooses the die.
resistancesNoResistances row, source-exact text.
creatureTypeYesCreature type, source text. Preserved verbatim into `core.race` per the guide Rule 16 'preserve original text'.
hitDiceCountYesNumber of hit dice (the count, e.g. 12 for a creature with 12d8 listed in HP).
spellcastingNoInnate spellcasting block per the guide Rule 4: the casting ability, save DC, and the spells grouped by their source frequency text. Vault formats the spell list as markdown per that rule and lands it as a single rules[] entry.
legendaryIntroNoIntro paragraph of the stat block's legendary section (the prose about how those actions work for this creature). Lands in notes[] under the name the guide Rule 8 gives. Individual legendary entries go in `actions[]` with the matching `type`.
additionalNotesNoAny free-form notes[] entries the LLM wants to author beyond the auto-generated challenge, legendary-intro, and alternate-form speed rows. Use sparingly — most stat-block content has a dedicated structured field above.
initiativeBonusNoThe listed initiative bonus. Pass it only if it differs from the bonus the sheet derives; vault keeps the difference in `offense.initiative.misc` per the guide Rule 17.
vulnerabilitiesNoVulnerabilities row.
damageImmunitiesNoSplit form: damage-only immunities, source-exact. Use only if the source has a separate damage immunities row.
damageResistancesNoSplit form: damage-only resistances, source-exact. Use only if the source has a separate damage resistances row.
conditionImmunitiesNoSplit form: condition-only immunities, source-exact. Use only if the source has a separate condition immunities row.
damageVulnerabilitiesNoSplit form: damage-only vulnerabilities, source-exact.
sourceProficiencyBonusNoOverride the PB derived from CR. Use only when the source stat block explicitly lists a PB other than the one its CR gives. A PB larger than the sheet's keeps the difference in misc automatically, per the guide Rule 15.

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.6/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Goes well beyond the annotations: it discloses that the vault back-derives base values and proficiency/expertise/misc flags, formats spell-list markdown, creates recharge trackables, generates challenge/legendary-intro/alternate-form notes, and auto-sets type, settings.autoPassiveBonuses and core.experience. It also states the input convention (caller passes source-text finals, vault computes stored bases), which is the key behavioral contract.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loaded with purpose and the replaced pattern, then the conversion behavior, then the guide pointer. Some clauses are long and dense, but each carries information an agent needs before calling; no filler sentences.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a 31-parameter, deeply nested, non-idempotent creation tool with an output schema, the description supplies the workflow, the replacement guidance, the derivation contract, the side effects, and a pointer to the authoritative field guide. Nothing an agent needs in order to call it correctly is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, so the schema already documents all 31 parameters (baseline 3). The description adds a cross-cutting semantic layer the schema cannot: the source-text-in / derived-value-out convention for AC, skills and attack bonuses, plus the pointer to the authoring guide as the per-field meaning reference.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb+resource ('Create a complete monster character in one call') and immediately distinguishes itself from the vault_create_character + vault_update_character sibling pattern. An agent can tell it is the monster-authoring entry point without opening the schema.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explicitly names the pattern it replaces (create_character + multiple update_character calls) and routes the agent to list_rulesets for ruleset codes and vault_get_authoring_guide for field conventions. It stops short of an explicit 'do not use for PCs, use vault_build_pc instead' exclusion, which the dense sibling set would have benefited from.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

vault_build_pcBuild a player characterAInspect

Assemble a complete, playable player character in one call from a flat draft of choices, in a ruleset with guided creation (the ruleset field's list). Vault validates every pick against the user's own + stock content and builds the full sheet — ability scores (with background bump), skills, saves, hit points, starting equipment + derived weapon actions, granted rules / feats / abilities, trackables, and a creation-recap note. Read vault_get_pc_creation_options first to get legal ids and pools. Required: name, classRuleId, abilityScoreMethod, abilityScoreAssignments, skillProficiencies, toolProficiencies, startingEquipmentLabel. Required when present: backgroundFeatRuleId (an open featOpen background's feat, from the originFeatCategory feats — the build rejects the draft without it). Optional: speciesRuleId, backgroundRuleId, backgroundSkillProficiencies (when the background grants skills as a choice), the background bump (backgroundBumpMode + backgroundBumpAssignments), backgroundFeatRuleId (as a swap on a fixed-feat background), languages, languageChoicePicks (background/species language-choice grants), alignment, description/image/appearances/token, and the choice maps (proficiencyChoicePicks, abilityChoices, speciesAbilityChoices, backgroundFeatChoices, equipmentChoices, weaponAbilityChoices, abilityBumpPicks) plus the spell maps (spellChoicePicks, spellListChoicePicks, preparedSpellPicks, castingAbilityPicks) for spellcasters / spell-list-choice grants. proficiencyChoicePicks and spellChoicePicks are keyed ":" and only needed where a grant's count is smaller than its option pool. castingAbilityPicks is required for any spellChoices block surfacing castingAbilityOptions — the projection only surfaces that array when a pick is genuinely needed (a spellListChoices block's ability pick rides its spellListChoicePicks entry as castingAbility instead). The projected spellChoices/spellListChoices arrays may hold null entries (blocks inert at the starting level) — count them when keying picks by index. A feat chosen via an ability's ruleChoice (in abilityChoices/speciesAbilityChoices) brings its own sub-choices — supply them in those same maps keyed by the picked feat's _id. A repeatable feat filling the background slot (backgroundFeatRuleId) instead prefixes its pick keys bg:<featId>. The created character is owned by the calling user and returned in full. On an invalid draft vault returns the specific reason (e.g. a pick out of pool, a wrong pick count, a missing required choice) as a tool error — fix the draft and retry.

ParametersJSON Schema
NameRequiredDescriptionDefault
nameYesCharacter name. Required.
imageNoCharacter portrait — `{ url }`.
tokenNoDefault battlemap token art — `{ url }`.
rulesetYesA ruleset with guided character creation: the one the options were read for with `vault_get_pc_creation_options`.
alignmentNo
languagesNoThe character's OWN chosen language names. The build adds any language the ruleset gives every character. `constants.languages.options` + `pickCount` are the conventional pool and count, but vault stores whatever is passed here — free-form names are allowed and the count is not enforced. (Languages a background/species GRANTS go in `languageChoicePicks`, not here.)
appearancesNoAppearance roster — `[{ url }]`. The portrait (`image`) is typically the default appearance.
classRuleIdYesRequired. `_id` of a base Class rule (from `vault_get_pc_creation_options({ kind: 'class' })`).
descriptionNoCharacter description / biography.
speciesRuleIdNo`_id` of the heritage rule (from `kind: 'species'`).
abilityChoicesNoPicks for a class ability's `choice` (ruleChoice). Key is the ability rule `_id`; value is exactly `choice.count` picked option `_id`s from `choice.options`. Each option carries a `type`. When a picked option carries its OWN sub-choices (any type — an Ability or a Feat), supply them in `proficiencyChoicePicks` / `spellChoicePicks` / `spellListChoicePicks` / `preparedSpellPicks` keyed by the picked option's `_id`, just like the background feat.
abilityBumpPicksNoAbility-score-increase picks for any applied rule carrying an `abilityScoreBump` (a feat / ability that raises a score by your choice). Key is the granting rule `_id`; value is `{ option, lines }`: `option` is the 0-based index of the chosen alternative in that bump's `options` (the player picks exactly ONE — the OR), and `lines` is parallel to that option's `lines`, each entry the lowercase ability names assigned to that line (the AND). Each line needs exactly its `count` distinct abilities drawn from its `eligible` pool (empty = any ability in the schema's abilities list), none exceeding its `max`. The build bakes the increases onto the ability scores before it derives the rest of the sheet. A `repeatable` feat filling the background slot keys `bg:<featId>` instead of `<featId>`.
backgroundRuleIdNo`_id` of a Background rule (from `kind: 'background'`).
equipmentChoicesNoResolves equipment groups in the chosen bundle. Key is the group parent item `_id` (a `startingEquipmentOptions[].items[]` entry that carries `group.options`); value is the picked member `_id`. Every group in the chosen bundle needs an entry.
spellChoicePicksNoPicks for `spellChoices` blocks across ALL applied rules (class/species/feat/abilities). Key is `"<ruleId>:<blockIndex>"` (the Rule `_id` and the 0-based index into that rule's `spellChoices` AS PROJECTED — the array may contain null entries holding the position of blocks that grant nothing at the starting level; count them when indexing, never compact the array). Value is the chosen spell `_id`s. Only supply where a block's `count` < its option-pool size — a whole-pool block is granted automatically. Each block's options come from `vault_get_pc_creation_options` (an applied ability/feat's `spellChoices[].options`). A `repeatable` feat filling the background slot prefixes its keys `bg:<featId>:<blockIndex>`.
toolProficienciesYesThe class tool picks. Exactly `class.toolChoices.count` names from `class.toolChoices.options`. If an option is a group, pick a concrete member name, not the group. Empty array if none.
abilityScoreMethodYesHow ability scores were chosen. See `constants.abilityScoreMethods` for the array / point-buy budget / costs.
backgroundBumpModeNoRequired when the background grants an ability bump; each mode's amounts are the wizard constants' `backgroundBumpModeOptions`.
preparedSpellPicksNoWhich spells the player keeps prepared, for rules carrying a `preparedSpells` count. Key is the granting rule `_id`; value is spell `_id`s drawn from the character's preparable granted spells — `spellChoices` picks, whole-pool fixed grants, and `spellListChoices` picks alike — EXCLUDING any granted by a block whose `prepared` flag is true (an always-prepared grant; the options projection ships `prepared` on each block so you can tell) and any the count does not cover (the rule authoring guide's preparedSpells section says which). The rule authoring guide.s preparedSpells section gives the required count; vault rejects picks that do not fit. A `repeatable` feat filling the background slot keys `bg:<featId>` instead of `<featId>`.
skillProficienciesYesThe class skill picks. Exactly `class.skillChoices.count` names, each from `class.skillChoices.options`, no duplicates. Empty array if the class grants no skill choices.
castingAbilityPicksNoSpellcasting-ability picks for `spellChoices` blocks that carry `castingAbilityOptions` (a grant that lets the player choose the casting ability). Key is `"<ruleId>:<blockIndex>"` (same keying as `spellChoicePicks`); value is ONE lowercase ability name from that block's `castingAbilityOptions`. The projection surfaces `castingAbilityOptions` only when a pick is genuinely required (a fixed ability or a single option self-resolves server-side) — so whenever you see the array, supply a pick or the build rejects the draft. The resolved ability is stamped on each granted spell (`spells[].castingAbility`). A `repeatable` background feat prefixes the key `bg:<featId>:<blockIndex>` (same keying as spellChoicePicks).
languageChoicePicksNoPicks for a background's or species' language-CHOICE grant (`background.languages.choose` / `species.languages.choose`). Key is the granting rule's `_id`; value is exactly `languages.choose.count` names from `languages.choose.options` (an empty options pool means any `constants.languages.options`). The grant's `languages.fixed` are auto-applied and need no pick. Distinct from `languages` (the character's own picks).
backgroundFeatRuleIdNoThe background's feat, from the `originFeatCategory` feats. REQUIRED when `background.featOpen` is true (an open slot — the build rejects the draft without it); optional on a fixed-feat background, where supplying it swaps the authored default. Must be a feat in the `originFeatCategory` (from `kind: 'feat'`).
spellListChoicePicksNoPicks for `spellListChoices` blocks (choose ONE of the block's lists, then spells from that one list). Key is `"<ruleId>:<blockIndex>"` (the projected array may contain null entries holding the position of blocks the build skips — count them when indexing, never compact); value is `{ category, picks }` where `category` is one of the block's `categories` and `picks` is `{ "<pickIndex>": [spellId, …] }` — the chosen spells for each pick, drawn from that pick's `optionsByCategory[category]`. When the block carries `castingAbilityOptions`, also set `castingAbility` (one lowercase ability name from those options) — the build rejects the draft without it. A `repeatable` feat filling the background slot prefixes its keys `bg:<featId>:<blockIndex>`.
weaponAbilityChoicesNoFor a weapon in the chosen bundle whose attack ability is a player pick: key is the item `_id`, value is the attack ability (one of the schema's enum).
backgroundFeatChoicesNoPicks for the background feat's `choice` (ruleChoice) AND for any choice carried by the feat's granted abilities. Key is the feat `_id` (its own choice) or the granted ability's `_id` (that ability's choice); value is the picked rule `_id`s.
speciesAbilityChoicesNoSame as `abilityChoices`, for a species ability's `choice`. A picked option's own sub-choices (any type — Ability or Feat) go in the proficiency/spell pick maps keyed by that option's `_id`.
proficiencyChoicePicksNoPicks for proficiencyChoices grants across ALL applied rules (class/species/feat/abilities). Key is `"<ruleId>:<grantIndex>"` (the Rule `_id` and the 0-based index into that rule's `proficiencyChoices`); value is the chosen names (skills/tools/saves/weapons/armor/languages). Only supply for grants where `count` < the option-pool size — fixed grants (count >= pool) are auto-applied and need no pick. A grant with `level: "expertise"` grants the expertise state rather than proficiency, from the pool the rule authoring guide describes (proficiencyChoices). A `repeatable` feat filling the background slot prefixes its keys `bg:<featId>:<grantIndex>` (not `<featId>:<grantIndex>`).
startingEquipmentLabelYesThe chosen equipment bundle — must equal one `class.startingEquipmentOptions[].label` exactly.
abilityScoreAssignmentsYesFinal ability scores by ability key, every key required. Must satisfy the chosen `abilityScoreMethod` as `constants.abilityScoreMethods` describes it (still send every value you intend).
abilityScorePointBudgetNoBudget override for an ability-score method that spends a budget. Defaults to that method's budget in `constants.abilityScoreMethods`. Ignored for a method without one.
backgroundBumpAssignmentsNoBackground ability-score bump per key, as `backgroundBumpMode` distributes it (each mode's amounts are the wizard constants' `backgroundBumpModeOptions`, from `vault_get_pc_creation_options` kind `constants`). Keys not bumped are omitted or 0. Only the background's `abilityScores` keys are eligible.
backgroundSkillProficienciesNoThe background skill picks, when the background grants skills as a CHOICE (`background.skillChoices`). Exactly `background.skillChoices.count` names from `background.skillChoices.options`, no duplicates. Parallel to `skillProficiencies` (the class picks). Omit when the background has no `skillChoices` block; a background's fixed `skillProficiencies` are auto-applied and need no pick.

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.6/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With annotations only flagging a non-read-only, non-idempotent mutation, the description carries real weight: it discloses that the build validates every pick against user+stock content, builds the full sheet, assigns ownership to the calling user, and returns it in full. It also specifies error behavior — invalid drafts surface the specific reason (out-of-pool pick, wrong count, missing choice) as a tool error to fix and retry.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The purpose and prerequisite are front-loaded, and for a 33-parameter tool with intricate choice-map keying most sentences do carry needed information. However, it is delivered as one monolithic paragraph with no structural separation, making the dense required/optional/keying/error sections harder to parse than they need to be.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a highly complex build tool with nested choice maps and an existing output schema, the description covers the prerequisite, the graded requirement levels, keying conventions, spellcasting edge cases, and failure semantics. Nothing an agent needs to assemble a valid draft and recover from rejection is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 97%, so the baseline is 3, but the description adds cross-cutting rules the schema presents piecemeal: the required-when-present semantics of backgroundFeatRuleId, the '<ruleId>:<grantIndex>' keying convention, and the 'bg:<featId>' prefixing for repeatable feats filling the background slot. It does not add genuinely new parameter meaning beyond consolidating schema-level detail, so it stops short of 5.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The opening sentence states a precise verb+resource ('Assemble a complete, playable player character in one call from a flat draft of choices') and scopes it to rulesets with guided creation. It enumerates the concrete artifacts produced (ability scores, skills, saves, HP, equipment, feats, trackables, recap note), which clearly separates it from raw-create siblings like vault_create_character.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It gives an explicit prerequisite ('Read vault_get_pc_creation_options first to get legal ids and pools') and a rich required/optional/required-when-present breakdown. It does not explicitly contrast with the adjacent siblings (vault_create_character, vault_level_up_pc), so the alternative-selection guidance is implied rather than stated.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

vault_clone_characterClone a vault characterAInspect

Duplicate any vault character the calling user can see — their own characters, stock template content, and other users' authored characters are all valid sources. The server does the deep-copy (stats, skills, items, rules, spells, trackables, all of it) — caller passes only the source id and optionally a new name. The new character is owned by the caller (not the source's original owner) and counts against the caller's character entitlement limit. When name is omitted, the clone is named <source name> (Copy). Use this instead of fetching the source sheet and re-POSTing it via vault_create_character.

ParametersJSON Schema
NameRequiredDescriptionDefault
idYesMongo `_id` of the source character to clone.
nameNoOptional name for the new character. Defaults to `<source name> (Copy)` when omitted, matching the web client's clone behavior. Whitespace-only values are rejected at the schema layer so a silently-trimmed-to-empty name can't reach the backend.

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.7/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Adds substantial behavior beyond annotations: deep-copy semantics, ownership transfer to the caller, entitlement/quota impact, and default naming when name is omitted. These are non-obvious consequences not inferable from readOnlyHint or destructiveHint.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Four tight, purposeful sentences. It front-loads the core scope, then covers mechanics, ownership/quota, and the alternative without filler or redundancy.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a two-parameter tool with an output schema, this is complete: it covers source scope, deep-copy behavior, ownership, quota effects, naming, and the correct alternative. Nothing essential is missing for an agent to invoke it correctly.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, and the schema already documents both parameters, including the default naming behavior and whitespace validation. The description reiterates that name is optional but adds no genuinely new parameter semantics.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource ('Duplicate any vault character') and enumerates valid source types, which clearly distinguishes it from vault_create_character and other vault tools. It also names the key alternative explicitly.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Directly tells the agent when to use this tool: whenever cloning any visible character. It names the alternative (vault_create_character) and explains why this tool should be preferred over fetching and re-POSTing.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

vault_create_characterCreate a vault characterInspect

Create a new character in the user's vault. Requires name and ruleset. The vault server fills the per-ruleset sheet skeleton (the ruleset's attributes, skills, defense scaffolding, and the rest) for any sections the caller omits — a minimal { name, ruleset } body produces the same shape the web and iOS clients create. The passthrough schema accepts richer structure when you want to set sections inline at create time. Set type: "monster" (lowercase) to mark a monster. The new character is owned by the calling user. Note: characters can be linked to active play campaigns; modify them with care if so.

ParametersJSON Schema
NameRequiredDescriptionDefault
coreNo
deadNo
nameYesCharacter name. Required.
typeNoCharacter type. Free-form per ruleset. Set to 'monster' (lowercase) to mark an authored monster; vault's character list endpoint filters that value out of the default catalog view.
imageNo
itemsNo
notesNo
rulesNo
speedNo
activeNo
skillsNo
spellsNo
stressNo
actionsNo
aspectsNo
defenseNo
offenseNo
rulesetYesRuleset code, from list_rulesets (the codes this account can use). Required. Restricted rulesets require an entitlement grant on the account — vault answers 403 for ungranted or unknown codes.
settingsNo
attributesNo
trackablesNo
descriptionNo
personalityNo

Output Schema

ParametersJSON Schema
NameRequiredDescription
_idNo
vault_create_itemCreate a vault itemBInspect

Create a new user-authored item of any of the ruleset's item types. Vault validates ruleset-specific fields (damage, properties, equip slots, weight); send them via the passthrough schema. The new item is owned by the calling user.

ParametersJSON Schema
NameRequiredDescriptionDefault
oglNo
costNoCost in gold pieces (max 2 decimal places). Vault enforces non-negativity and precision.
nameYesDisplay name. Required.
typeYesItem type. Required.
usesNo
imageNo
activeNo
damageNo
effectNo
sourceNo
weightNo
_parentNoParent item ObjectId for variant items.
healingNo
masteryNoWeapon mastery name, for rulesets whose weapons carry one, as the ruleset's catalog names it.
rulesetNoRuleset code, from list_rulesets.
summaryNoShort one-line summary.
durationNo
rollModsNo
publisherNo
actionTypeNoAuthoring hint — when set, the character sheet's rule modal shows an 'Add to Actions' button that mints an action row with this `type`.
armorClassNoBase AC value the armor provides.
damageDiceNoBase damage expression (e.g. '1d8').
damageTypeNoDamage types as an array of strings (most items have one type; some have multiples).
diceFloorsNo
equipSlotsNoAllowed equip slot ids, from the ruleset's own slots (an existing item's equipSlots, via vault_get_item, shows them).
parametersNo
propertiesNo
ruleChoiceNo
weaponTypeNoWeapon category, as the ruleset's catalog names it (vault_search_items shows them).
descriptionNoFull item description. Markdown is supported.
resistancesNo
statBonusesNo
mechanicsKeyNo
spellChoicesNo
armorCategoryNoArmor category, as the ruleset's catalog names it (vault_search_items shows them).
prerequisitesNo
forcedMovementNo
maxDexModifierNoCap on the DEX bonus this armor allows, from the item's source text.
preparedSpellsNo
abilityScoreSetNo
damageReductionNo
recurringDamageNo
abilityScoreBumpNo
diceReplacementsNo
spellListChoicesNo
prerequisitesLogicNo
proficiencyChoicesNo
stealthDisadvantageNo
strengthRequirementNo

Output Schema

ParametersJSON Schema
NameRequiredDescription
_idNo

TDQS

B3.2/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint=false, destructiveHint=false and idempotentHint=false, so the write/non-idempotent nature is covered. The description usefully adds that Vault validates ruleset-specific fields and that the item is owned by the calling user, but omits error behavior, permission requirements, and what happens on validation failure.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Three sentences, front-loaded with the core action and scope, with no filler. Tight and readable given the complexity of the underlying schema.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness3/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a 49-parameter authoring tool with 33% schema coverage, the description is thin: it does not point to vault_get_authoring_guide or vault_search_items for valid type/property names, which is the main obstacle to calling it correctly. An output schema exists, so return values need not be described, and annotations cover the safety profile.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is only 33% across 49 parameters, so the burden partly falls on the description, which names only four field groups (damage, properties, equip slots, weight) and points at a 'passthrough schema' without explaining it. It adds some orientation but does not compensate for the undocumented deep nested structures.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource ('Create a new user-authored item') and scopes it to 'any of the ruleset's item types', which distinguishes it from vault_update_item / vault_get_item. It never names a sibling, so differentiation is inferable from the verb rather than explicit.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines2/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

There is no when-to-use or when-not guidance and no reference to alternatives such as vault_update_item for editing or vault_search_items for canonical property/type values. The clause about ruleset-specific validation implies a ruleset must be chosen first, but that inference is left to the agent.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

vault_create_ruleCreate a vault ruleCInspect

Create a new user-authored rule of any rule type (the type field lists them). The new rule is owned by the calling user and is a 'house rule' unless the caller is an admin. Vault validates the payload; missing required fields return a vault error.

ParametersJSON Schema
NameRequiredDescriptionDefault
ageNo
oglNo
featNoMongo `_id` reference (24-character hex string).
nameYesDisplay name. Required.
sizeNo
typeNoRule category. Required at create time; vault rejects without it.
usesNo
imageNo
rangeNoHow far the ability reaches when invoked: `kind`, plus `distance` and its `unit` for a kind that takes a distance. Absent: the rule authoring guide (vault_get_authoring_guide, entityType 'rule') gives the default.
speedNo
activeNo
damageNo
effectNo
hitDieNo
sourceNo
_parentNoMongo `_id` reference (24-character hex string).
actionsNoAction-cost marker, for rulesets whose rules carry one; the value is the source text.
healingNo
rulesetNoRuleset code, from list_rulesets.
summaryNoShort one-line summary.
durationNo
featOpenNo
keywordsNo
rollModsNo
abilitiesNo
languagesNo
publisherNo
actionTypeNoAuthoring hint — when set, the character sheet's rule modal shows an 'Add to Actions' button that mints an action row with this `type`.
categoriesNo
diceFloorsNo
parametersNo
repeatableNoA rule that may be taken/granted more than once, each time as a distinct instance with its own sub-choices — a repeatable feat, or a class ability its class grants at several levels.
ruleChoiceNo
descriptionNoFull rule body. Markdown is supported.
resistancesNo
statBonusesNo
toolChoicesNo
creatureTypeNo
mechanicsKeyNo
savingThrowsNo
skillChoicesNo
spellChoicesNo
abilityScoresNo
actionEconomyNoWhat invoking the ability costs on a turn. The rule authoring guide (vault_get_authoring_guide, entityType 'rule') gives the absent default. Distinct from the mechanics actionType (a kind-of-action label).
armorTrainingNo
multiclassingNoWhat multiclassing INTO this class grants (weapon/armor lists apply fixed; skillChoices/toolChoices render pickers). Absent = no multiclass proficiencies.
prerequisitesNo
castingAbilityNoThe ability this rule's spellcasting keys off. Author it on a class's Spellcasting ability rule; vault's creation and level-up wizards write it to the character-wide Spellcasting Ability (first-wins, never overwriting), and a multiclass whose ability differs stamps its granted spells per-entry. Distinct from a spell block's castingAbility, which overrides per grant. Absent = the rule says nothing about the character's casting ability.
forcedMovementNo
preparedSpellsNo
spellAbilitiesNo
abilityScoreSetNo
damageReductionNo
recurringDamageNo
abilityScoreBumpNo
diceReplacementsNo
levelProgressionNo
spellListChoicesNo
casterProgressionNoHow this class contributes to the combined multiclass spell-slot pool; the engine applies each progression's rule. Authorable on a base class or a subclass (a subclass that grants the casting carries it). Absent = non-caster.
startingEquipmentNo
toolProficienciesNo
prerequisitesLogicNo
proficiencyChoicesNo
skillProficienciesNo
weaponProficienciesNo
defaultAbilityScoresNo

Output Schema

ParametersJSON Schema
NameRequiredDescription
_idNo

TDQS

C2.9/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare this is a non-read-only, non-destructive, non-idempotent write. The description adds real value beyond that by disclosing ownership (owned by the calling user), that the created rule is a 'house rule' unless admin, and that validation failures on missing required fields surface as a vault error. It stops short of describing return shape or the complexity of authoring a 66-field payload, so it is above baseline but not rich.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Three tight sentences, front-loaded with the core action, then ownership, then error behavior. No filler, though it is far too short relative to the payload's complexity rather than being bloated.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness2/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a tool with 66 parameters at 23% schema description coverage and deep nested objects, the description omits the single most important routing hint available: the rule authoring guide (vault_get_authoring_guide, entityType 'rule') that the schema repeatedly references for defaults. An output schema exists so return values need not be explained, but the authoring gap is significant.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters2/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is only 23% across 66 parameters, so the description carries a heavy compensation burden, yet it names only the `type` field and a generic 'missing required fields' note. It adds little meaning beyond what the schema already encodes for `type`, and barely addresses the vast undocumented surface.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource (create a user-authored rule) and scopes it with 'of any rule type,' which distinguishes it from vault_create_spell and vault_create_item. It does not explicitly name those siblings, so it stops short of the 5 benchmark, but the resource is unambiguous.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines2/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

No when-to-use or when-not guidance and no pointer to the alternative paths for authoring a rule (e.g. vault_get_authoring_guide, which the schema itself cites for defaults). The 'unless the caller is an admin' clause is an ownership condition, not usage guidance.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

vault_create_spellCreate a vault spellAInspect

Create a new user-authored spell or power. Vault validates ruleset-specific required fields (level, casting time, components, range, duration, etc.); send them via the passthrough schema. The new spell is owned by the calling user.

ParametersJSON Schema
NameRequiredDescriptionDefault
oglNo
areaNoArea of effect. `shape`; `size` (ft); `width` for a line.
nameYesDisplay name. Required.
rankNoRank, for rulesets whose spells carry one. Free-form.
typeNoSpell type (the ruleset's name for a spell). Required at create.
usesNo
levelNoSpell level, within the schema's range. The spell authoring guide gives the convention.
rangeNoRange. `kind`; `distance` and its `unit` for a ranged spell (absent unit = feet).
activeNo
damageNo
effectNo
ritualNoRitual tag: the spell can be cast as a ritual.
schoolNoSpell school name.
sourceNo
_parentNoParent spell ObjectId for variant spells.
actionsNoAction-cost marker, for rulesets whose spells carry one; the value is the source text.
classesNoClass-membership list for rulesets whose spells do not use `categories` (the spell authoring guide covers `categories`). Free-form per ruleset.
healingNo
rulesetNoRuleset code, from list_rulesets.
summaryNoShort one-line summary.
durationNoSpell duration. `unit`; `count` for a timed unit; concentration flag; upTo flag for a non-concentration capped duration ("Up to 1 minute").
rollModsNo
publisherNo
actionTypeNoAuthoring hint — when set, the character sheet's rule modal shows an 'Add to Actions' button that mints an action row with this `type`.
categoriesNoGo-forward class membership. The field `spellChoices[].allowedCategories` filters on; the vault UI labels it 'Class(es)'. Free-form, taggable.
componentsNoComponents: verbal/somatic/material flags, plus material text, gp cost, and consumed flag.
diceFloorsNo
parametersNo
ruleChoiceNo
castingTimeNoCasting time. `unit`, plus `count` for a timed unit.
descriptionNoFull spell body. Markdown is supported.
higherLevelNoScaling text: what changes when the spell is cast at a higher level or scales with the caster, source text.
resistancesNo
statBonusesNo
mechanicsKeyNo
spellChoicesNo
prerequisitesNo
forcedMovementNo
preparedSpellsNo
abilityScoreSetNo
damageReductionNo
reactionTriggerNoFor a casting time taken in response to a trigger, the trigger text, source text.
recurringDamageNo
abilityScoreBumpNo
diceReplacementsNo
spellListChoicesNo
prerequisitesLogicNo
proficiencyChoicesNo

Output Schema

ParametersJSON Schema
NameRequiredDescription
_idNo

TDQS

A3.6/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare non-read-only, non-destructive, non-idempotent behavior, so the bar is lower. The description adds genuinely useful context beyond them: server-side validation of ruleset-specific fields, a 'passthrough schema' that accepts arbitrary additional properties, and explicit ownership by the calling user.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Three compact sentences, front-loaded with the action, then the validation/passthrough caveat, then ownership. No filler; the only mild weakness is that the passthrough note is packed into a dense clause.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness3/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

An output schema exists, so return values need no explanation. But for a 48-parameter, ruleset-dependent create tool, the description should ideally flag the prerequisite lookups (ruleset code, authoring guide) and the specific validated fields; it does the latter loosely and omits the former.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

With 48 parameters and only 44% schema description coverage, the description carries a burden it only partially meets. It lists several expected fields (level, casting time, components, range, duration) and points at the passthrough schema, but most of the 48 nested parameters remain undocumented here.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource ('Create a new user-authored spell or power') and scopes it to authoring by the calling user. It does not explicitly name siblings like vault_update_spell or vault_get_spell, but the phrase 'user-authored' distinguishes it from library-read tools well enough to act on.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Implied usage is clear (author a new spell), and it hints that ruleset-specific required fields determine what to send. However, it never states when to use this versus vault_update_spell or vault_create_item, nor does it name vault_get_authoring_guide / list_rulesets as prerequisites, leaving routing to inference.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

vault_delete_characterDelete a vault characterA
DestructiveIdempotent
Inspect

Permanently delete a character by id. Caution: a deleted character is removed from any campaigns or expeditions referencing it. Run vault_get_character first to inspect linkage.

ParametersJSON Schema
NameRequiredDescriptionDefault
idYesMongo `_id` of the vault document.

Output Schema

ParametersJSON Schema
NameRequiredDescription
idNo
deletedNo

TDQS

A4.2/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already indicate destructiveHint=true, idempotentHint=true, and readOnlyHint=false, so the description need not restate those. It adds valuable behavioral context beyond annotations by disclosing the cascade effect (removal from referencing campaigns/expeditions) and recommending a pre-deletion inspection step. No contradiction with annotations.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is two sentences with no filler. The first sentence immediately states the action and target; the second delivers the critical caution and prerequisite. This is front-loaded, focused, and every word earns its place.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a single-parameter delete operation, the description covers the essential concerns: permanence, cascade effects, and a recommended pre-step. The presence of an output schema means return-value details do not need to be in the description. Minor gaps remain (e.g., failure conditions if the character is referenced), but the description is complete enough for an agent to call it correctly.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%; the schema already defines 'id' as the Mongo `_id` of the vault document. The description merely echoes 'by id' without adding further semantic detail (e.g., id format, validation constraints, or relationship to other resources). Baseline 3 is appropriate because the schema carries the parameter meaning.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states a specific verb ('Permanently delete') and resource ('a character by id'), making the tool's purpose unambiguous. It also differentiates from similar siblings like vault_delete_item or vault_delete_rule by explicitly targeting characters, and the 'vault' prefix separates it from play_delete_character.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description provides clear context: deletion is permanent and cascades to campaigns/expeditions referencing the character. It gives a direct prerequisite ('Run vault_get_character first to inspect linkage'), which is actionable guidance, though it does not explicitly mention when not to use this tool or alternative tools like vault_unlink_character.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

vault_delete_itemDelete a vault itemB
DestructiveIdempotent
Inspect

Permanently delete a user-authored item by id. Cannot delete stock content.

ParametersJSON Schema
NameRequiredDescriptionDefault
idYesMongo `_id` of the vault document.

Output Schema

ParametersJSON Schema
NameRequiredDescription
idNo
deletedNo

TDQS

B3/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already indicate destructiveHint=true and idempotentHint=true, so the description correctly states 'permanently delete' which aligns. However, it does not add context about irreversibility, potential cascading effects, or authorization requirements. The description adds minimal value beyond the annotations, but it does clarify permanence, which is slightly beyond the structured hints.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is only 2 sentences and is front-loaded with the action and restriction. It is concise and to the point, with no superfluous information. It could be slightly more structured, but it is efficient.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness3/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the tool's simplicity (one param, no output schema details, annotations cover destructive nature), the description is adequate but does not address how to distinguish vault items from stock content or what happens after deletion. Since an output schema exists, return value explanation is not needed, but the restrictions and implications are not fully fleshed out.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters2/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The schema description for the 'id' parameter is minimal ('Mongo `_id`'), and the tool description does not elaborate on what kind of identifier is needed or how to obtain it. Since schema coverage is 100%, but the schema description provides little semantic depth, the description should compensate but does not. It only says 'by id', which is redundant with the schema.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the verb 'delete' and the resource 'vault item', and explicitly notes that stock content cannot be deleted, which distinguishes it from other delete tools. It could be improved by contrasting with similar delete tools like vault_delete_character, but it is otherwise clear.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines2/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description does not specify when to use this tool versus alternatives, such as vault_delete_character, or when not to use it. It only mentions the restriction on stock content, which is a constraint but not a usage guideline. No exclusions or alternative routing are provided.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

vault_delete_ruleDelete a vault ruleA
DestructiveIdempotent
Inspect

Permanently delete a user-authored rule by id. Cannot delete stock content. Pair with vault_get_rule first to confirm the target.

ParametersJSON Schema
NameRequiredDescriptionDefault
idYesMongo `_id` of the vault document.

Output Schema

ParametersJSON Schema
NameRequiredDescription
idNo
deletedNo

TDQS

A4.2/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare destructiveHint=true and idempotentHint=true, so the description doesn't need to restate those. The description adds the key behavioral constraint that stock content cannot be deleted, which is beyond the annotations. It also clarifies the operation is permanent, which reinforces the destructive nature. This adds value beyond the structured data without contradicting it.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two sentences with no filler. The first sentence states the action and scope; the second provides a critical safety guideline. Every word earns its place, and the most important information (permanence, user-authored only) is front-loaded.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a single-parameter delete tool with a full output schema and annotations covering destructive/idempotent behavior, the description is nearly complete. The only minor gap is that it doesn't describe what happens if the id doesn't exist or if the user lacks permission, but the output schema likely covers error responses. The 'pair with vault_get_rule' guidance compensates for potential misuse. A 4 is fair given the tool's simplicity.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%: the only parameter 'id' is fully described as the Mongo `_id` of the vault document. The description adds that the id refers to a user-authored rule, which is a slight semantic enrichment, but the schema already carries the main meaning. Baseline 3 is correct because the schema does the heavy lifting and the description adds only marginal context.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states a specific verb ('Permanently delete'), a specific resource ('user-authored rule'), and identifies it by id. It also distinguishes from stock content deletion, which is a clear scope boundary. The title 'Delete a vault rule' is reinforced with the permanent and user-authored qualifiers, making the purpose unambiguous.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description explicitly instructs to pair with vault_get_rule first to confirm the target, which is a clear usage guideline. It does not explicitly name alternatives or when-not-to-use, but the sibling list includes vault_delete_character, vault_delete_item, vault_delete_spell, and the 'Cannot delete stock content' exclusion provides context. A 4 is appropriate because it gives actionable guidance but doesn't fully enumerate alternatives.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

vault_delete_spellDelete a vault spellA
DestructiveIdempotent
Inspect

Permanently delete a user-authored spell by id. Cannot delete stock content.

ParametersJSON Schema
NameRequiredDescriptionDefault
idYesMongo `_id` of the vault document.

Output Schema

ParametersJSON Schema
NameRequiredDescription
idNo
deletedNo

TDQS

A4.3/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already mark the operation as destructive and non-read-only, and the description adds meaningful context: the deletion is 'permanent' and limited to user-authored spells. This goes beyond the annotation hints and clarifies an important behavioral boundary. No contradiction with annotations.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two short sentences with no filler. The core action and the key restriction are both stated up front, and every word contributes to the agent's understanding.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a single-parameter delete operation with annotations covering destructive behavior and an output schema present, the description is complete. The permanent-deletion warning and stock-content restriction give the agent the essential operational context it needs.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The schema already fully documents the single `id` parameter as a Mongo `_id` with 100% coverage. The description mentions deletion 'by id' but adds no additional semantic detail beyond what the schema provides, so the baseline score of 3 is appropriate.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description uses a specific verb and resource: 'Permanently delete a user-authored spell by id.' It also adds a scoping constraint ('Cannot delete stock content') that clearly distinguishes the tool's intended target from other content types. This is easily differentiated from sibling tools like vault_delete_character or vault_delete_rule.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description makes the key usage condition explicit: only user-authored spells can be deleted, and stock content cannot. It does not name alternative tools, but the resource-specific scope and the exclusion are sufficient for an agent to decide when this tool applies.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

vault_detach_companionDetach a companion from a characterA
DestructiveIdempotent
Inspect

Remove a companion row from a Main character's sheet by the ROW's _id (from the companions[] array — not the buddy's own character id). Detaching an 'owned' row leaves the referenced character in the user's vault untouched; detaching a 'link' row discards the locally-tracked overlay counters (the source character is untouched either way). Response is { companions, updatedAt }; ADOPT the returned updatedAt as the Main character's fresh stamp.

ParametersJSON Schema
NameRequiredDescriptionDefault
idYesMongo `_id` of the Main character carrying the companion row.
companionIdYesThe companion ROW's `_id` from the Main character's `companions[]` array — NOT the buddy character's own `_id`. Read it off vault_get_character.

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.8/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Beyond the destructiveHint annotation, the description discloses that detaching an 'owned' row leaves the referenced character untouched, while a 'link' row discards local overlay counters. It also explains the response shape and instructs the agent to adopt the returned `updatedAt`, adding valuable operational context.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is dense but every sentence earns its place: the action, the identifier caveat, the two row-type behaviors, and the response/updatedAt instruction are all operational essentials. It is well-structured and front-loaded with the primary action.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

The tool has two fully described parameters, clear annotations, and an output schema, and the description covers the behavioral nuances and response handling. An agent has everything it needs to select and invoke this tool correctly.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters5/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is already 100%, but the description adds critical disambiguation: `companionId` is the row `_id` from `companions[]`, not the buddy character's id, and should be sourced from vault_get_character. This prevents a highly plausible misuse that the schema alone might not fully communicate.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description uses a specific verb ('Remove') and resource ('companion row from a Main character's sheet') and clarifies the exact identifier by which removal happens. It clearly differentiates from related vault operations by specifying the row `_id` rather than a character id.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description gives clear context for when this tool applies by distinguishing 'owned' rows from 'link' rows and explaining the different consequences. It does not explicitly name alternatives like vault_attach_companion, but the use case is evident from the semantics and sibling tools.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

vault_get_authoring_guideGet a vault authoring guideA
Read-onlyIdempotent
Inspect

Fetch a markdown reference guide that teaches the conventions for authoring a specific entity type in a specific ruleset. Returns the full markdown body, including front-matter metadata (ruleset, entityType, version) at the top. Entity types: 'monster' — monster stat-block authoring (the field map, the stat block math, action types, spell formatting, resistances/immunities, keywords, a worked example), authored via vault_build_monster or vault_create_character + vault_update_character; 'rule' — classes / species / backgrounds / feats / abilities (the type taxonomy, the parent→Ability grant model, type-specific section fields, and the shared mechanics blocks: proficiencyChoices, spellChoices, spellListChoices, preparedSpells, freeCast, uses, ruleChoice, statBonuses), authored via vault_create_rule + vault_update_rule; 'spell' — the spell detail header (casting time / range / area / components / duration), the categories (Class(es)) membership convention, and the damage/healing/effect mechanics blocks, authored via vault_create_spell + vault_update_spell. Pass the ruleset code you are authoring for (list_rulesets gives the codes). Call this BEFORE authoring the matching entity so the result follows the established conventions instead of inferring shape from one-off samples. Returns a 'not found' tool error when the requested entityType / rulesetCode combination does not have a published guide yet.

ParametersJSON Schema
NameRequiredDescriptionDefault
entityTypeYesEntity the guide covers: 'monster', 'rule' (classes / species / backgrounds / feats / abilities), or 'spell'. Lowercase. A ruleset / entity pair with no published guide returns not found.
rulesetCodeNoRuleset code, from list_rulesets. Use the code, not the display label.

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.4/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint/idempotent/no-destructive, so safety is covered. The description adds genuinely new behavior: it returns the full markdown body with front-matter metadata and returns a 'not found' tool error for unpublished entityType/rulesetCode pairs. That error-path disclosure is the key value beyond annotations.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Purpose and usage are front-loaded, and the entity-type breakdown is dense but earns its length because it tells the agent what to author next. It is a single long paragraph, making it slightly heavy to scan, and a couple of clauses (e.g. restating rulesetCode from list_rulesets) do not add much.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a two-param read-only lookup with an output schema already defining the return shape, the description covers purpose, routing to siblings, parameter meaning, and the failure mode (published-guide not found). Nothing an agent needs in order to call it correctly is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, so the baseline is 3, but the description adds meaning beyond the schema by spelling out what each entityType value encompasses (stat-block math for 'monster', parent→Ability grant model for 'rule', categories membership for 'spell') and clarifying that rulesetCode must be the code, not the display label.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description opens with a specific verb+resource ('Fetch a markdown reference guide') and scopes it precisely to entity type + ruleset. It then enumerates exactly what each guide covers ('monster', 'rule', 'spell'), so an agent can distinguish it from the sibling authoring tools (vault_create_rule, vault_build_monster, etc.) without opening any schema.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It gives an explicit when-to-use directive ('Call this BEFORE authoring the matching entity so the result follows the established conventions instead of inferring shape from one-off samples') and points at list_rulesets for the ruleset code. It stops short of naming alternative tools or explicit exclusions, so it is strong but not fully complete.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

vault_get_characterGet a vault characterA
Read-onlyIdempotent
Inspect

Fetch one character document by id. Defaults to a summary shape: combat-relevant top-level fields (attributes, defense, offense, AC, HP, actions, skills) preserved; bulk text bodies on populated rule/item/spell refs and inline snapshots trimmed; notes/trackables reduced to names + key fields. Pass detail: 'full' for the populated shape with every description inline. The companions[] array (buddy ties — see vault_attach_companion) rides along untrimmed in both shapes, overlay state included; each row's _ref is a bare character id you can fetch with this tool. linkGroup, when present, is the id shared by this persona's linked sheets in other rulesets (created via vault_spawn_linked_character); it rides reads only and is not writable through the update tool.

ParametersJSON Schema
NameRequiredDescriptionDefault
idYesMongo `_id` of the vault document.
detailNoResponse shape. 'summary' (default) trims the bulk text bodies on the populated rules / items / spells refs and on the inline snapshots, preserving combat-relevant top-level fields. 'full' returns the populated document with every description inline.summary

Output Schema

ParametersJSON Schema
NameRequiredDescription
_idNo

TDQS

A4.7/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already establish readOnly/not destructive/idempotent, and the description adds substantial behavioral detail: what the summary shape trims, what `full` restores, that `companions[]` rides along untrimmed with `state`, and that `linkGroup` is read-only. No contradiction with annotations.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is dense but every sentence earns its place: the core action is front-loaded, followed by shape behavior, then related fields and cross-tool references. No filler or redundancy.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given an output schema exists and annotations cover the read-only safety profile, the description is complete for an agent to call this tool correctly: it explains the id-based fetch, both response shapes, companion array handling, and linkGroup read semantics. Nothing important is left missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, so the baseline is 3. The description adds meaningful operational meaning beyond the schema, especially for `detail`: it explains exactly what gets preserved, trimmed, or inlined in each shape. It doesn't add anything new about `id`, but the schema already covers that fully.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

Opens with a specific verb+resource: 'Fetch one character document by id.' The scope is unambiguous and the name vault_get_character matches the action, while the description clearly differentiates it from list/search tools and other vault_get_* tools.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description gives clear context for choosing the summary vs. full detail shape, explains how companion `_ref` values can be resolved by this tool, and warns that `linkGroup` is read-only via the update tool. It does not explicitly name when to prefer this over vault_search_characters, but the usage is otherwise clear.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

vault_get_itemGet a vault itemA
Read-onlyIdempotent
Inspect

Fetch one item document by id, including damage info, weight, properties, equip slots, and ammo settings. Pair with vault_search_items to locate the id first.

ParametersJSON Schema
NameRequiredDescriptionDefault
idYesMongo `_id` of the vault document.

Output Schema

ParametersJSON Schema
NameRequiredDescription
_idNo

TDQS

A4.1/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint=true, idempotentHint=true, and destructiveHint=false, so the read-only nature is covered. The description adds the list of returned fields, which is useful context beyond the annotations, but it does not disclose any additional behavioral traits like error conditions, auth requirements, or return format. Since the annotations carry the safety profile, the description adds moderate value but doesn't go further.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is two concise sentences with no unnecessary words. The core action ('Fetch one item document by id') is front-loaded, and the pairing instruction is useful without redundancy. Every sentence earns its place.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a one-parameter, read-only getter with an output schema and comprehensive annotations, the description is complete. It tells the agent what the tool does, what fields are included, and how to obtain the id (via vault_search_items). The output schema covers return values, and annotations cover safety, so no further detail is necessary for correct invocation.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The schema already provides 100% coverage for the single parameter 'id' with a clear description ('Mongo `_id` of the vault document'). The description simply says 'by id', adding no new semantic information beyond what the schema already states. Therefore, the baseline of 3 is appropriate.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states a specific verb ('Fetch'), resource ('item document'), and key operation (by id). It lists the included fields (damage info, weight, properties, equip slots, ammo settings), which distinguishes it from other vault_get_* tools, and explicitly names the sibling 'vault_search_items' as the way to locate the id first.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description gives an explicit workflow: 'Pair with vault_search_items to locate the id first.' This clearly tells the agent when to use this tool (when an id is available and full item details are needed) and points to the alternative for finding the id. It doesn't explicitly state when not to use it, but the pairing instruction is practical and sufficient for a get-by-id tool.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

vault_get_levelup_optionsRead a character's level-up planA
Read-onlyIdempotent
Inspect

Read the level-up plan for a character whose ruleset has guided level-up (vault answers an error naming the ruleset otherwise) — the same computation vault's web wizard renders. Without classRuleId: the CHOOSER (the character's class entries with stored levels, the multiclass candidates each with warn-only prerequisite warnings[], xp.minimumForNext, atMaxLevel). A character with NO class entries (a hand-made sheet) gets RECORD mode instead: needsClassRecord: true plus recordOptions[] (every usable base class with subclasses[] and its subclassLevel) — record the existing classes with vault_record_pc_classes first, then re-read; the target plan and vault_level_up_pc reject a class-less character. With classRuleId: the TARGET PLAN for advancing that class one level — features[] (gained at the new level) / subclassFeatures[] / growth[] (held rules whose choice counts grew; their counts are DELTAS, "pick N more") each carrying its open choice blocks in the creation-option shape, plus multiclassGrants (entering a new class: fixed proficiency lines + skill/tool pickers), hitPoints {hitDie, average, conModifier}, prerequisiteWarnings[] (multiclass entry is warn-only, the player may proceed), spellSlots (combined multiclass pool preview, null when the plan has no combined pool), and xp {current, minimumForNewTotal}. Add subclassRuleId (at a subclass level, before committing the pick) to preview that candidate's features. ruleChoice pools arrive prerequisite-FILTERED — every listed option is one the character qualifies for at the level being gained. Read this before vault_level_up_pc and key every pick off what it returns.

ParametersJSON Schema
NameRequiredDescriptionDefault
characterIdYes`_id` of the character to level (must belong to the calling user).
classRuleIdNoOmit for the CHOOSER (the character's class entries with their stored levels, the multiclass candidates with warn-only prerequisite warnings, the XP floor for the next level, atMaxLevel). Supply a base Class rule `_id` — one of the chooser's `classEntries[].classRuleId` to advance a held class, or a `multiclassOptions[]._id` to enter a new class — for the TARGET PLAN: `features[]` / `subclassFeatures[]` / `growth[]` (each feature in the creation option shape with its open choice blocks: `choice` {label,count,options}, spellChoices (each block carries `prepared` — true = its spells land always-prepared and are EXCLUDED from the preparedSpellPicks pool), spellListChoices (same `prepared` flag), preparedSpells, proficiencyChoices, abilityScoreBump; `growth[]` entries are already-held rules whose counts grew this level — their `count`s are DELTAS, "pick N more"), `multiclassGrants` (when entering a new class), `hitPoints` {hitDie, average, conModifier}, `prerequisiteWarnings[]` (warn-only), `spellSlots` (the combined multiclass pool preview, null when the plan has no combined pool), `openPickCount`, and `xp` {current, minimumForNewTotal}. ruleChoice pools arrive PREREQUISITE-FILTERED (an unqualified pick is also rejected on apply).
subclassRuleIdNoWith classRuleId, previews a tentative subclass pick before committing: the candidate's features (and their open choices) resolve into `subclassFeatures[]`. The pick itself still travels in `vault_level_up_pc.abilityChoices`, keyed by the class's subclass-choice ability.

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.8/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations only declare a safe read (readOnlyHint, idempotentHint); the description adds substantial behavior beyond that: the error thrown for non-guided rulesets, RECORD mode fallback with needsClassRecord/recordOptions, warn-only prerequisite semantics, DELTA counts on growth[], and prerequisite-FILTERED choice pools. This is rich disclosure that structured fields do not provide.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loaded with the core purpose, then organized by mode (Without classRuleId / With classRuleId / subclassRuleId). It is very long and parenthetical-heavy, but nearly every clause carries actionable detail (mode keys, field semantics, cross-tool flow) rather than filler.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Despite an output schema existing, the description fully equips the agent: it explains both response shapes, the fallback path, prerequisite filtering, and the downstream call sequence. Nothing needed to select or invoke the tool correctly is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100% and the schema descriptions already document each parameter in depth, so the baseline is 3. The description nonetheless adds mode-selection semantics (omit classRuleId for CHOOSER, supply it for TARGET PLAN) and clarifies subclassRuleId is a pre-commit preview whose pick still travels through vault_level_up_pc, which goes beyond the schema's field-level text.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States the specific verb and resource ('Read the level-up plan for a character whose ruleset has guided level-up') and precisely delineates the two output modes keyed on classRuleId (CHOOSER vs TARGET PLAN). It is clearly distinguishable from siblings lke vault_level_up_pc and vault_get_pc_creation_options.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explicitly says 'Read this before vault_level_up_pc and key every pick off what it returns,' names the alternative path for a class-less character ('record the existing classes with vault_record_pc_classes first, then re-read'), and notes the error case when the ruleset is wrong. When-to-use and dependencies are fully covered.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

vault_get_pc_creation_optionsRead character-creation optionsA
Read-onlyIdempotent
Inspect

Read the legal choices for guided character creation — the same projections vault's web wizard reads. Pass ruleset (one with guided creation: the ruleset field's list; list_rulesets gives each code's label) and kind to select one list: 'class' / 'species' / 'background' / 'feat' return the option projections (the calling user's own content plus stock, each option carrying its nested choices: skillChoices, toolChoices, startingEquipmentOptions, and per applied ability/feat — proficiencyChoices, spellChoices, spellListChoices, preparedSpells, and choice whose options carry a type; a background option also carries skillChoices + languages, a species option carries languages; background bump modes / feat, etc.); 'feat' returns every feat (a feat picked via an ability's choice carries its own proficiency/spell sub-choices); 'constants' returns the static reference data (skill list with attributes, ability-score methods with each method's data, language options + pick count, alignments, background bump modes, max ability score, and originFeatCategory — the feat category the background's open feat slot is restricted to; filter the 'feat' list to it for the background pick). Use this BEFORE vault_build_pc so every id and pick you send is one the user is actually entitled to. Start with 'constants' and 'class', then read 'species' / 'background' / 'feat' as the build takes shape.

ParametersJSON Schema
NameRequiredDescriptionDefault
kindYesWhich creation list to read. 'class' / 'species' / 'background' / 'feat' return the option projections (the user's own + stock content they may pick, with each option's nested choices — skillChoices, toolChoices, startingEquipmentOptions, and per applied ability/feat: proficiencyChoices {types,count,options}, spellChoices {count,options,prepared}, spellListChoices {categories,picks[].optionsByCategory,prepared}, preparedSpells {count} (a block's `prepared: true` = its spells land always-prepared and are EXCLUDED from the preparedSpellPicks pool), abilityScoreBump {options[].lines[]:{amount,count,eligible,max}} (supply the player's pick via `vault_build_pc.abilityBumpPicks`), and `choice` {count,options} where each option carries a `type`. The spellChoices / spellListChoices arrays are INDEX-ALIGNED with the authored blocks — a null entry holds the position of a block that grants nothing at the starting level; skip it when rendering but count it when keying picks. A 'background' option ALSO carries its own `skillChoices {count,options}` (a background skill-choice grant → supply picks via `vault_build_pc.backgroundSkillProficiencies`) and `languages {fixed, choose:{count,options}}`; a 'species' option carries `languages {fixed, choose}`. For a `languages.choose` grant, supply the picks via `vault_build_pc.languageChoicePicks` keyed by that rule's `_id`; `languages.fixed` apply automatically). 'feat' returns EVERY feat (the background slot uses the `originFeatCategory` feats; a feat picked via an ability's `choice` may be any) — a picked feat carries its own proficiency/spell sub-choices. Each 'feat' option carries `repeatable`; a `repeatable` feat filling the background slot keys its `vault_build_pc` picks with a `bg:` prefix. 'constants' returns the static reference data (skill list, ability-score methods and each method's data, language options, alignments, background bump modes, max ability score, and originFeatCategory — the feat category the background's open feat slot is restricted to; filter the 'feat' list to it for the background pick). Read 'constants' plus 'class' first; read 'species'/'background'/'feat' as the build takes shape.
rulesetNoA ruleset with guided character creation. Send the same ruleset to `vault_build_pc`.

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.4/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already cover the safety profile (readOnlyHint, idempotentHint, destructiveHint=false), but the description adds substantial behavioral context: it returns the calling user's own content plus stock, it mirrors the web wizard's projections, it explains nested choice structures, index-aligned null placeholders, repeatable feat key prefixes, and the originFeatCategory restriction. This is rich context beyond what annotations provide.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness2/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is extremely long and dense, and large portions duplicate the already exhaustive input schema descriptions. While the purpose and sequencing are front-loaded, the sheer volume means many sentences do not earn their place, making it hard to scan.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the complexity of guided character creation and the presence of a rich output schema, the description is complete enough: it covers ordering, entitlement filtering, what each kind returns, and key relationships to vault_build_pc. Return-value details are appropriately left to the output schema.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100% and the input schema already exhaustively documents both parameters, including each kind's returned structures. The description largely restates the same kind semantics, adding only a minor reference to list_rulesets for ruleset labels. Baseline 3 is appropriate when the schema does the heavy lifting.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb ('Read') and resource ('legal choices for guided character creation'), and distinguishes itself from the build tool by positioning as the pre-read step before vault_build_pc. An agent can immediately tell this tool returns option projections rather than performing a mutation.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explicitly says to use this BEFORE vault_build_pc, gives an ordering ('Start with constants and class, then read species/background/feat as the build takes shape'), and points to list_rulesets for ruleset labels. It leaves no ambiguity about when and in what sequence to call it.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

vault_get_ruleGet a vault ruleA
Read-onlyIdempotent
Inspect

Fetch one rule document by id, including nested abilities, requirements, ability score bonuses, and starting equipment references. Pair with vault_search_rules to locate the id first.

ParametersJSON Schema
NameRequiredDescriptionDefault
idYesMongo `_id` of the vault document.

Output Schema

ParametersJSON Schema
NameRequiredDescription
_idNo

TDQS

A4.3/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint=true, idempotentHint=true, and destructiveHint=false, so the safety profile is covered. The description adds behavioral detail by specifying that the returned document includes nested abilities, requirements, ability score bonuses, and starting equipment references, going beyond the bare schema.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two sentences, both functional: the first states the operation and result contents, the second gives the practical lookup workflow. There is no redundant phrasing or filler.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a simple one-parameter getter with an output schema present and annotations covering safety, the description is complete. It identifies the resource, the necessary id, the included content, and how to obtain the id via vault_search_rules. No critical usage information is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, and the schema already defines id as the MongoDB `_id` of the vault document. The description merely says "by id," adding no new semantic information about the parameter. This matches the baseline for high schema coverage.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description opens with a specific verb and resource: "Fetch one rule document by id," which clearly distinguishes this from vault_search_rules (search/listing) and vault_create_rule/update_rule/delete_rule (mutations). It also enumerates the nested content included, leaving no ambiguity about what this tool returns.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description gives an explicit workflow: "Pair with vault_search_rules to locate the id first." This tells the agent when this tool is appropriate after a search. It does not spell out when not to use it, but for a single-document fetch tool this is acceptable and clear context.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

vault_get_spellGet a vault spellA
Read-onlyIdempotent
Inspect

Fetch one spell document by id, including its level, casting time, range, components, duration, and full description. Pair with vault_search_spells to locate the id first.

ParametersJSON Schema
NameRequiredDescriptionDefault
idYesMongo `_id` of the vault document.

Output Schema

ParametersJSON Schema
NameRequiredDescription
_idNo

TDQS

A4.3/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint=true, idempotentHint=true, and destructiveHint=false, so the safety profile is fully covered. The description adds useful context about what the fetched document includes (level, casting time, range, components, duration, full description), but does not mention missing-id or not-found behavior. Overall it adds some value beyond the annotations without being richly behaviorally descriptive.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two sentences with no wasted words. The first sentence defines the operation and what is returned; the second sentence gives the companion workflow. Everything included earns its place.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

This is a simple get-by-id operation with one well-documented parameter, rich annotations, and an output schema present. The description covers the essential workflow and the pointer to vault_search_spells closes the only real ambiguity: where the id comes from.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100% and the single parameter id is already documented in the schema as a Mongo `_id` of the vault document. The description reinforces that this id is the retrieval key and points to vault_search_spells as the source of the id, but it does not need to add more detail because the schema already fully explains the parameter.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states a specific verb ('Fetch'), a specific resource ('one spell document'), and the retrieval mechanism ('by id'), while enumerating the key fields returned. It is clearly distinguishable from siblings like vault_search_spells, which locates documents rather than fetching a single one.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description explicitly names vault_search_spells as the companion tool to use first for locating the id, giving the agent a concrete workflow. This handles the main routing decision: search to find the id, then fetch by id.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

vault_level_up_pcLevel up a player characterAInspect

Advance a character one level in a class, in one call, from a flat draft of choices, for a ruleset with guided level-up (vault answers an error naming the ruleset otherwise). A class-less character (no Class entries) is rejected — record its existing classes with vault_record_pc_classes first. Vault validates every pick against the plan's pools (prerequisites enforced; grown choices demand only their delta counts) and mutates the character: the class entry's stored level bumps (or a new class entry lands with the class's multiclassGrants), the level's features snapshot onto the sheet (a subclass picked through the class's subclass-choice ability lands as its own entry and cascades its features), ability-score increases bake, HP and hit dice grow per the hitPoints choice, use-counters resize (spent uses stay spent), the combined multiclass spell-slot pool reconciles, core.class updates to " , ...", XP floors at the new level's minimum (or your exact xp), and a level-up note records the choices; the engine applies every rule behind those changes. Read vault_get_levelup_options first — required: characterId, classRuleId, hitPoints. Supply abilityChoices for every feature choice the plan surfaced (including the subclass pick and grown choice lists), the sub-pick maps for anything the picked options themselves carry, multiclassSkillProficiencies/multiclassToolProficiencies when entering a class, and optional exact xp. The updated character and a summary of what changed are returned. On an invalid draft vault returns the specific reason as a tool error — fix the draft and retry; if a surfaced pick genuinely cannot be satisfied, allowIncomplete: true applies the level and skips the shortfall instead.

ParametersJSON Schema
NameRequiredDescriptionDefault
xpNoThe character's total XP after this level-up, for tables tracking exact XP. Must be >= the plan's `xp.minimumForNewTotal`; omit to let vault floor the stored XP at that minimum.
hitPointsYesHow the level's hit points are gained: `method` is one of the schema's methods (the plan's `hitPoints` fields carry what each one uses); `value` is a die the PLAYER rolled, for a method that takes one.
characterIdYes`_id` of the character to level (must belong to the calling user).
classRuleIdYesRequired. The base Class rule to advance one level — a held class entry (its stored level bumps) or a class the character doesn't hold yet (multiclass: a new class entry is stamped). From the chooser's `classEntries[].classRuleId` / `multiclassOptions[]._id`.
abilityChoicesNoruleChoice picks, keyed by the OWNING rule's `_id`: a gained feature's choice (the class's subclass-choice ability — value = the picked subclass `_id`; a choice among feats — value = the picked feat `_id`) AND a grown held rule's choice (`growth[]` entries — supply the NEW picks only, the delta count). A picked option's own sub-choices (a feat's skill picks, its abilityScoreBump) go in the other maps keyed by the picked option's `_id`, exactly as in `vault_build_pc`. Pools are prerequisite-filtered; an unqualified pick rejects the draft.
allowIncompleteNoSanctioned partial apply: `true` lets vault accept UNDER-filled pick families — the level lands and only what was picked is granted; the shortfall is simply skipped (the player can edit the sheet later). Overfilled, duplicate, out-of-pool, and prerequisite-failing picks still reject. Use it as the escape when a surfaced pick cannot be satisfied; never as a shortcut past picks you can supply.
abilityBumpPicksNoAbility-score-increase picks for a gained rule carrying an `abilityScoreBump`: `{ option, lines }` keyed by the granting rule's `_id`, same shape as `vault_build_pc`. The engine applies whatever the increase changes elsewhere on the sheet.
spellChoicePicksNoPicks for spellChoices blocks on gained/grown rules, keyed `"<ruleId>:<blockIndex>"` (authored index — the projected array may hold nulls; count them). Grown blocks demand only the DELTA count ("learn N more spells").
preparedSpellPicksNo"Prepare N more" picks for rules whose preparedSpells count grew, keyed by the granting rule's `_id`. The pool is the character's UNPREPARED granted leveled spells plus any picked this level-up; send exactly the plan's surfaced count.
castingAbilityPicksNoSpellcasting-ability picks for blocks surfacing `castingAbilityOptions`, keyed like spellChoicePicks.
spellListChoicePicksNoPicks for a NEWLY gained rule's spellListChoices — `{ category, picks, castingAbility? }` keyed `"<ruleId>:<blockIndex>"`, exactly as in `vault_build_pc`.
proficiencyChoicePicksNoPicks for proficiencyChoices grants on gained/grown rules, keyed `"<ruleId>:<grantIndex>"` — same keying and rules as `vault_build_pc`. Grown grants demand only the DELTA count the plan surfaced. An EXPERTISE grant picks from the pool the rule authoring guide describes (vault_get_authoring_guide, entityType .rule., proficiencyChoices); vault rejects picks that do not fit.
multiclassToolProficienciesNoTool picks for the entered class's `multiclassGrants.toolChoices` (multiclass only): exactly `count` names from its (group-expanded) options.
multiclassSkillProficienciesNoSkill picks for the entered class's `multiclassGrants.skillChoices` (multiclass only): exactly `count` names from its options.

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.5/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations only give readOnly=false/destructive=false/idempotent=false, so the description carries most of the burden — and it delivers: it discloses validation against plan pools, prerequisite enforcement, delta-count semantics, the full mutation set (level bump, feature snapshot, HP/hit-dice growth, counter resize, spell-slot reconcile, class string, XP floor), and error/retry behavior. The one gap is no explicit warning about reversibility/undo of these mutations, which matters for a non-idempotent write.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness3/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The purpose is front-loaded, but the bulk is one dense run-on paragraph with nested em-dash lists that is hard to parse and would benefit from segmentation. Most content earns its place, but the wall-of-text structure costs readability.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a 14-parameter mutation tool with nested objects and an output schema (so return values needn't be restated), the description covers prerequisites, mutation semantics, parameter wiring, and error handling. Nothing an agent needs to invoke it correctly is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is already 100%, so the baseline is 3, but the description genuinely adds invocation-level meaning beyond the schema: which maps each pick family belongs to, that grown choices demand only their delta counts, prerequisite-filtered pools, and that sub-picks are keyed by the picked option's _id 'exactly as in vault_build_pc'. This is more than the schema alone conveys.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource ('Advance a character one level in a class, in one call, from a flat draft of choices') and scopes it (single level, one call, flat draft). It clearly differentiates from siblings by naming vault_get_levelup_options as the required prerequisite and vault_record_pc_classes as the fix for class-less characters.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explicit when-to-use: 'Read vault_get_levelup_options first'; explicit exclusion: class-less characters are rejected and must be recorded via vault_record_pc_classes first; and an explicit escape hatch with its condition ('if a surfaced pick genuinely cannot be satisfied, allowIncomplete: true'). This covers use, alternatives, and when-not.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

vault_list_linked_charactersList a character's linked sheetsA
Read-onlyIdempotent
Inspect

List the linked sibling sheets of a character the user owns — every OTHER sheet in its linkGroup (the same persona in other rulesets, created via vault_spawn_linked_character). Returns summary rows (_id, name, ruleset, image, dead, active, linkGroup); follow with vault_get_character on a returned id for a full sheet. A character with no linkGroup returns an empty list. 404 for an unknown or unowned character.

ParametersJSON Schema
NameRequiredDescriptionDefault
idYesMongo `_id` of the character (owned by the calling user).

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.8/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With annotations already covering readOnlyHint, idempotentHint, and destructiveHint, the description adds substantive behavioral context: it returns only summary rows, returns an empty list when there is no linkGroup, and returns 404 for unknown or unowned characters. This ownership/error behavior goes beyond the annotations and does not contradict them.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The purpose is front-loaded in the first sentence, and the description is compact—covering output shape, follow-up workflow, and error/edge cases in three sentences. The field enumeration overlaps somewhat with the declared output schema, but the overall structure is scannable and free of unrelated detail.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a single-parameter read-only list tool, the description covers the purpose, ownership precondition, output semantics, empty-list edge case, error behavior, and the appropriate next tool for full details. Combined with the annotations and output schema, an agent has everything needed to call the tool correctly.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The schema already describes the single `id` parameter as the Mongo _id of an owned character, so the baseline is 3. The description adds meaningful nuance by clarifying that this id refers to the source character and that the result contains every OTHER sheet in its linkGroup, meaning the input character itself is excluded from the output.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description opens with a precise action and resource: 'List the linked sibling sheets of a character the user owns — every OTHER sheet in its linkGroup.' It clearly distinguishes itself from vault_get_character by stating it returns summary rows rather than full sheets, and it explicitly excludes the input character from the result set.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description gives clear context for when to use the tool: pass an owned character id and get its linked sibling sheets. It also names the explicit alternative follow-up, 'follow with vault_get_character on a returned id for a full sheet,' which tells the agent when to switch to the full-sheet tool, and it documents edge cases (empty list, 404).

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

vault_record_pc_classesRecord a class-less character's existing classesAInspect

The class-less on-ramp to the level-up flow. A hand-made character with no Class entries on its sheet can't level up (vault rejects the plan and the apply) — this tool records the class(es) and level(s) the character is ALREADY playing so the wizard can take over at the next level. It stamps identity snapshots ONLY: no features, proficiencies, HP, or trackables are granted — the sheet is trusted to already carry everything. Call vault_get_levelup_options first: RECORD mode (needsClassRecord: true) ships recordOptions[] (base classes with subclasses[] and subclassLevel) and totalLevel, the character's XP-derived level. The recorded levels must sum to EXACTLY that totalLevel (XP is the authority; vault never rewrites it) and a row may carry a subclass only at/above the option's subclassLevel. Rejected once any class entry exists. On success vault sets each class snapshot's stored level, attaches subclasses, updates core.class, appends a note, and returns { character, summary } — then call vault_get_levelup_options again for the normal chooser.

ParametersJSON Schema
NameRequiredDescriptionDefault
classesYesOne row per class the character already has, distinct classes only. The levels MUST sum to exactly the RECORD-mode chooser's `totalLevel` (the character's XP-derived level) — vault rejects any other split and never rewrites XP.
characterIdYes`_id` of the class-less character (must belong to the calling user).

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.6/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations declare this is a write operation that is not idempotent and not destructive; the description goes well beyond that, disclosing that only identity snapshots are stamped (no features, proficiencies, HP, or trackables), that levels must sum exactly to totalLevel, and that the tool sets stored levels, attaches subclasses, updates core.class, and appends a note. Destructive semantics could be slightly clearer given destructiveHint=false while the write mutates the sheet, but overall the disclosure is strong.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is dense and front-loaded, leading with the reason the tool exists before the mechanics. It is on the long side and repeats some schema constraints verbatim, but nearly every sentence carries workflow or validation information an agent needs.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a constrained write tool with a rich input schema, an output schema, and full annotations, the description supplies the full workflow, validation rules, and side effects. Nothing an agent needs to invoke it correctly is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, so the baseline is 3, but the description adds the cross-row constraint that levels must sum to exactly totalLevel and that a subclass is valid only at/above the option's subclassLevel. That relational meaning is genuinely beyond the per-field schema text, though much of it is echoed rather than new.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource (records the class(es) and level(s) a character is already playing) and explicitly frames it as the 'class-less on-ramp to the level-up flow', which cleanly separates it from siblings like vault_level_up_pc and vault_get_levelup_options. The agent can tell exactly what the tool does and when it is the wrong tool.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Gives explicit prerequisites and sequencing: call vault_get_levelup_options first, work from RECORD mode (needsClassRecord: true), then call it again for the normal chooser. It also states the exclusion condition (rejected once any class entry exists), so both when-to-use and when-not-to-use are covered.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

vault_search_charactersSearch vault charactersA
Read-onlyIdempotent
Inspect

Search PCs and NPCs (any character whose type is NOT the lowercase monster marker) the user owns, plus stock template characters. Use this to locate a player character or NPC the user has authored. Authored monsters are hidden — for creature stat blocks use the dedicated vault_search_monsters tool instead. Defaults to a compact summary shape (identification + image + class/race/background + linkGroup — the id tying a persona's per-ruleset linked sheets together; sheets sharing a linkGroup are the same persona in different rulesets); pass detail: 'full' to receive each character's full sheet (attributes, skills, rules, items, spells) inline.

ParametersJSON Schema
NameRequiredDescriptionDefault
nameNoSubstring match on character name (case-insensitive). Use `^name$` for an exact match.
skipNoPagination offset; pair with `limit` to walk results.
sortNoComma-separated field list. Prefix with `-` for descending (e.g. `-updatedAt,name`).
typeNoCharacter type filter (substring, case-insensitive). '^PC$' / '^NPC$' for the common user-authored cases. To search authored monsters, use the dedicated `vault_search_monsters` tool — this character search hides them by default (the lowercase `monster` type marker is filtered out unless you opt in via that sibling tool).
limitNoPage size; defaults to 50 when omitted. Hard cap of 200.
detailNoResponse shape. 'summary' (default) returns identification + summary fields; 'full' returns the complete document shape (every field inline) that non-MCP clients receive by default.summary
rulesetNoRuleset code, from list_rulesets.

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultsNo
paginationNo

TDQS

A4.6/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare read-only/idempotent/non-destructive, so the safety profile is covered. The description adds real behavioral context beyond that: authored monsters are hidden by default, the default return is a compact summary and 'detail: full' inlines the entire sheet, and linkGroup ties per-ruleset linked sheets to one persona. It does not describe pagination behavior or rate limits, keeping it short of a 5.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Purpose and the monster exclusion are front-loaded, and each sentence carries information. It is dense and long for a search tool, but nearly every clause (linkGroup, detail modes, monster routing) earns its place.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a 7-parameter read tool with an output schema, the description covers scope, sibling routing, the hidden-monster rule, and return-shape selection. Nothing an agent needs to call it correctly is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so the baseline is 3. The description nevertheless adds meaning for the `detail` parameter by contrasting the 'summary' shape (identification + image + class/race/background + linkGroup) with 'full' (attributes, skills, rules, items, spells inline), and it defines what linkGroup represents.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb+resource ('Search PCs and NPCs... plus stock template characters') and precisely defines scope by the lowercase 'monster' type marker. It explicitly distinguishes itself from the sibling 'vault_search_monsters', so an agent can route correctly without opening either schema.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

'Use this to locate a player character or NPC the user has authored' gives an explicit when-to-use, and 'for creature stat blocks use the dedicated vault_search_monsters tool instead' names the alternative and the condition that selects it. Nothing is left to inference.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

vault_search_itemsSearch vault itemsA
Read-onlyIdempotent
Inspect

Search the item library the user has access to (stock items plus their own house items). Use this to locate an item by name, type (the catalog's own item types), or ruleset. Defaults to a compact summary shape (identification + summary + weight + cost + publisher / source); pass detail: 'full' to receive each item's full description and properties array inline.

ParametersJSON Schema
NameRequiredDescriptionDefault
nameNoSubstring match on item name (case-insensitive). Use `^name$` for an exact match.
skipNoPagination offset; pair with `limit` to walk results.
sortNoComma-separated field list. Prefix with `-` for descending (e.g. `-updatedAt,name`).
typeNoItem type (substring, case-insensitive). Vault item types are ruleset-specific strings; an unfiltered search shows the types a ruleset's catalog uses.
limitNoPage size; defaults to 50 when omitted. Hard cap of 200.
stockNotrue = official content only; false = user-authored only; omit to include both.
detailNoResponse shape. 'summary' (default) returns identification + summary fields; 'full' returns the complete document shape (every field inline) that non-MCP clients receive by default.summary
rulesetNoRuleset code, from list_rulesets.

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultsNo
paginationNo

TDQS

A4.1/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare the safe read-only, idempotent profile, so the description's contribution is the response-shape behavior: default to a compact summary and the requirement to pass detail:'full' for inline properties. That is genuine behavioral context beyond the annotations.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two sentences, front-loaded with scope and purpose before the response-shape detail. The second sentence is dense but every clause carries meaning; no filler.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For an eight-parameter search tool with an output schema present, the description covers purpose, scope, and response shape without needing to explain return values. Pagination behavior is left to the schema's skip/limit descriptions, which is acceptable.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so every parameter is already documented. The description restates name/type/ruleset filtering and the detail default, adding only the nuance that item types are catalog/ruleset-specific — helpful but largely redundant with the schema baseline.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb (search) and resource (item library) and scopes it precisely: stock items plus the user's own house items. This distinguishes it cleanly from the many sibling search tools (vault_search_spells, vault_search_rules, vault_search_characters, vault_search_monsters).

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explicitly says when to use it — 'locate an item by name, type, or ruleset' — giving the agent concrete selection criteria among filter dimensions. It does not, however, name the sibling search tools or state exclusions, so an agent must infer the item-vs-spell/rule boundary from the resource name.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

vault_search_monstersSearch vault monstersA
Read-onlyIdempotent
Inspect

Search authored monsters (characters with the lowercase type: monster marker) the user owns, plus any stock template monsters. This is the right tool for creature stat-block lookups; vault_search_characters deliberately hides monsters by default and this sibling exists so the LLM doesn't have to remember the filter trick. The type filter is baked into the call. Defaults to a compact summary shape; pass detail: 'full' to receive each monster's full stat block (attributes, defense, offense, AC, HP, actions, skills) inline. Pair with vault_get_character on a returned id for the full document.

ParametersJSON Schema
NameRequiredDescriptionDefault
nameNoSubstring match on monster name (case-insensitive). Use `^name$` for an exact match.
skipNoPagination offset; pair with `limit` to walk results.
sortNoComma-separated field list. Prefix with `-` for descending (e.g. `-updatedAt,name`).
limitNoPage size; defaults to 50 when omitted. Hard cap of 200.
detailNoResponse shape. 'summary' (default) returns identification + summary fields; 'full' returns the complete document shape (every field inline) that non-MCP clients receive by default.summary
rulesetNoRuleset code, from list_rulesets.

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultsNo
paginationNo

TDQS

A4.6/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already cover the safety profile (readOnly, idempotent, non-destructive, closed-world), so the bar is lower. The description adds real behavioral context: the `type: monster` filter is baked into the call, results default to a compact shape, and `detail: 'full'` inlines full stat blocks. It stops short of covering pagination or rate behavior, but the value-added disclosure is solid.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loads the core purpose in the first clause and proceeds logically through sibling differentiation, response shape, and follow-up. Four dense sentences with no filler, though it is near the upper bound of ideal length.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

An output schema exists, so return values need not be spelled out, yet the description still summarizes the two response shapes. It covers routing, the baked-in filter, response detail, and chaining, leaving nothing an agent needs to call it correctly missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, so baseline is 3. The description goes beyond the schema by explaining the implicit baked-in type filter (which is not even a parameter) and clarifying the practical effect of `detail: 'full'` (full stat block inline vs compact summary), adding meaning above the raw enum description.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb+resource ('Search authored monsters... the user owns, plus any stock template monsters') and explicitly distinguishes itself from the sibling `vault_search_characters`, explaining why the separate tool exists. An agent can tell exactly what this returns without opening either schema.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Provides explicit when-to-use ('the right tool for creature stat-block lookups'), why-not-the-sibling ('vault_search_characters deliberately hides monsters by default'), and a follow-up pairing ('Pair with vault_get_character on a returned id'). Routing is unambiguous.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

vault_search_rulesSearch vault rulesA
Read-onlyIdempotent
Inspect

Search the rules library the user has access to (stock content plus their own house rules). Use this to locate a rule by name, type (the type field lists the rule types), or ruleset. Defaults to a compact summary shape (identification + summary + categories + publisher / source); pass detail: 'full' to receive each rule's full description and embedded sub-document arrays inline.

ParametersJSON Schema
NameRequiredDescriptionDefault
nameNoSubstring match on rule name (case-insensitive). Use `^name$` for an exact match.
skipNoPagination offset; pair with `limit` to walk results.
sortNoComma-separated field list. Prefix with `-` for descending (e.g. `-updatedAt,name`).
typeNoRule category to filter to.
limitNoPage size; defaults to 50 when omitted. Hard cap of 200.
stockNotrue = official/WOTC content only; false = user-authored house rules only; omit to include both.
detailNoResponse shape. 'summary' (default) returns identification + summary fields; 'full' returns the complete document shape (every field inline) that non-MCP clients receive by default.summary
rulesetNoRuleset code, from list_rulesets.

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultsNo
paginationNo

TDQS

A4.4/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnly/idempotent/non-destructive, so the safety profile is covered. The description adds real behavioral value by disclosing the default response shape and the opt-in `detail: 'full'` payload expansion, which changes what the caller receives.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two sentences, front-loaded with scope and purpose, then the filter axes, then the response-shape default. No filler or repetition.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With 8 optional params, an output schema, and complete annotations, the description covers the decision-relevant knobs (filters and detail mode). Pagination/sort/stock are left to the schema, which is acceptable but a brief note on paging would make it fully self-sufficient.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, so the baseline is 3. The description goes further by explaining what each `detail` mode actually returns (identification/summary/categories/publisher vs full description plus embedded sub-document arrays) and by framing the filterable fields, adding meaning beyond the schema's own wording.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb+resource ('Search the rules library') plus the access scope (stock content plus user house rules), and names the three lookup axes (name, type, ruleset). An agent can distinguish it from vault_get_rule and list_rulesets without opening either schema.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

'Use this to locate a rule by name, type, or ruleset' gives clear positive usage context, and the mention of ruleset codes implies list_rulesets as a feeder. It stops short of explicit exclusions (e.g., 'use vault_get_rule when you already have an id').

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

vault_search_spellsSearch vault spellsA
Read-onlyIdempotent
Inspect

Search the spell library the user has access to (stock spells plus their own house spells). Use this to locate a spell or power by name, ruleset, or type. Defaults to a compact summary shape (identification + summary + level + school + classes + categories + publisher / source); pass detail: 'full' to receive each spell's full description inline.

ParametersJSON Schema
NameRequiredDescriptionDefault
nameNoSubstring match on spell name (case-insensitive). Use `^name$` for an exact match.
skipNoPagination offset; pair with `limit` to walk results.
sortNoComma-separated field list. Prefix with `-` for descending (e.g. `-updatedAt,name`).
typeNoSpell type (the ruleset's name for a spell).
limitNoPage size; defaults to 50 when omitted. Hard cap of 200.
stockNotrue = official content only; false = user-authored only; omit to include both.
detailNoResponse shape. 'summary' (default) returns identification + summary fields; 'full' returns the complete document shape (every field inline) that non-MCP clients receive by default.summary
rulesetNoRuleset code, from list_rulesets.

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultsNo
paginationNo

TDQS

A4.3/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already cover the read-only, idempotent, non-destructive profile, so the bar is lower. The description still adds real context: the library scope (stock + house content) and the default compact response shape with an opt-in for full descriptions.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two front-loaded sentences with no waste: scope first, then use case, then the response-shape toggle. Every clause earns its place.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With an output schema present and full parameter coverage, the description needn't explain return values. It completes the picture by stating which content is searchable and the default response shape, which is enough for correct invocation.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, and the schema already documents the `detail` enum thoroughly ('summary' vs 'full'), name matching, and pagination. The description largely restates the `detail` behavior and adds little parameter meaning beyond the schema, so baseline 3 applies.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb+resource ('search the spell library') and pins down scope precisely: stock spells plus the user's own house spells. This distinguishes it cleanly from siblings like vault_get_spell (single fetch) and vault_search_items/rules.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Gives a clear use case ('locate a spell or power by name, ruleset, or type') and routes to the full-detail mode. It stops short of naming the retrieval alternative (vault_get_spell) or stating when search is the wrong choice, so it's clear context but no explicit exclusions.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

vault_spawn_linked_characterSpawn a linked character sheet in another rulesetAInspect

Create a linked sibling sheet for a character the user owns, in a different ruleset — the same persona with sheets in multiple rulesets, tied together by a shared linkGroup id. The server builds the new sheet from the target ruleset's template and copies only the descriptive/identity fields in the sync manifest (name, description, image, appearance, personality, and similar); mechanical and build data (class, level, attributes, skills, rules/items/spells, notes) stays ruleset-local and starts fresh. After the spawn, edits to a manifest field on any linked sheet cascade to its siblings automatically. Play campaign assignments of the source are replicated onto campaign legs matching the new ruleset where they exist. One sheet per ruleset per group: vault answers 409 when the source is already that ruleset or a linked sibling already occupies it, 403 for an ungranted restricted ruleset, and 404 for an unknown or unowned source. This is NOT vault_clone_character — clone deep-copies the whole ruleset-specific sheet; spawn deliberately does not.

ParametersJSON Schema
NameRequiredDescriptionDefault
idYesMongo `_id` of the source character (owned by the calling user).
rulesetNoRuleset code for the new linked sheet, from list_rulesets (the codes this account can use). Required. Must differ from the source's ruleset; restricted rulesets require an entitlement grant (vault answers 403).

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.8/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations only carry the generic readOnly/destructive/idempotent/openWorld flags, but the description adds substantial behavior: which fields are copied vs. left ruleset-local, the cascade-on-edit semantics, campaign-leg replication, and concrete 403/404/409 failure modes. This is far more than the annotations convey.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The core action is front-loaded in the first clause, and every sentence carries information (copy manifest, cascade, campaign legs, error codes, sibling contrast). It is dense and long for a single paragraph, which slightly reduces scannability.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a mutation with an output schema and annotations, the description covers the source/output construct, field-copy rules, cascade behavior, campaign replication, and error responses. An agent has everything needed to invoke it correctly and interpret failures.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is already 100%, so the baseline is 3, but the description adds meaning beyond the schema: the one-sheet-per-ruleset-per-group rule and the 409 conflict when the source is already that ruleset or a sibling occupies it. It does not elaborate on the `id` parameter, keeping it from a 5.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states a precise verb and resource ('Create a linked sibling sheet for a character the user owns, in a different ruleset') and immediately explains what a 'linked' sheet is (same persona, shared linkGroup). It explicitly contrasts itself with the sibling vault_clone_character, so an agent can disambiguate without opening either schema.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It names the alternative tool and the exact selection condition: 'This is NOT vault_clone_character — clone deep-copies the whole ruleset-specific sheet; spawn deliberately does not.' It also states the preconditions (user-owned source, different ruleset, entitlement for restricted rulesets) that gate legitimate use.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

vault_update_characterUpdate a vault character
Idempotent
Inspect

Patch fields on an existing character by id. Only supplied fields change, with one distinction: object sub-docs (defense, core, offense, speed, personality, settings) deep-merge — nested keys you omit are preserved — but ARRAY fields (items, spells, rules, skills, actions, trackables, attributes, notes) are atomic: the array you send replaces the stored array wholesale. To add or edit one array entry, vault_get_character first, modify the returned array, and send the complete array back. Sending null for a field is treated the same as omitting it (the field keeps its current value) — null does NOT clear; to clear a text field send an empty string. This is also the canonical tool for editing a play campaign character's HP, conditions, or inventory; play characters are pointers to vault characters and play has no direct character-write endpoint. AC caution: when the character's settings.autoPassiveBonuses is true (the default for new characters in rulesets with sheet automation), the armor and shield rows of defense.armorClass are derived from equipped items and recomputed on every sheet load — change AC by setting equipped on the character's armor/shield items, not by writing those rows; when the toggle is false, defense.armorClass is manually authored and writing it directly is correct. Caution: mutations may affect any active play campaign or expedition referencing this character. Consider running vault_get_character first to inspect linkage. REQUIRES baseUpdatedAt: copy updatedAt from a fresh vault_get_character read; a stale or fabricated value is rejected with OUT_OF_SYNC and nothing is written — writing from memory of an earlier read is not possible. companions is NOT writable here (it is stripped): manage buddy ties with vault_attach_companion / vault_detach_companion, and a linked buddy's tracked values with vault_update_companion_state. linkGroup is NOT writable here either (also stripped): linked-sheet group membership is created by vault_spawn_linked_character and only vault's unlink endpoint clears it.

ParametersJSON Schema
NameRequiredDescriptionDefault
idYesMongo `_id` of the character to update.
coreNo
deadNo
nameNoCharacter display name.
typeNoCharacter type. Free-form per ruleset. Set to 'monster' (lowercase) to mark an authored monster; vault's character list endpoint filters that value out of the default catalog view.
imageNo
itemsNo
notesNo
rulesNo
speedNo
activeNo
skillsNo
spellsNo
stressNo
actionsNo
aspectsNo
defenseNo
offenseNo
rulesetNoRuleset code, from list_rulesets (the codes this account can use). Restricted rulesets require an entitlement grant on the account — vault answers 403 for ungranted or unknown codes.
settingsNo
attributesNo
trackablesNo
descriptionNo
personalityNo
baseUpdatedAtYesREQUIRED proof that you are working from the latest version: copy the `updatedAt` value verbatim from a FRESH read of this exact record (use the matching get tool first). Values from memory, from an earlier conversation, or guessed timestamps are rejected with OUT_OF_SYNC and nothing is written. After a successful update, the response carries the new `updatedAt` — use that for any follow-up write.

Output Schema

ParametersJSON Schema
NameRequiredDescription
_idNo
vault_update_companion_stateUpdate a linked companion's tracked valuesA
Idempotent
Inspect

Write a LINK-mode companion row's transient overlay — the locally-tracked hit points, temp HP, hit dice, death saves, exhaustion, stress marks, and trackable/free-cast counters for a buddy the user doesn't own. The source character is never written. The state you send replaces the row's stored overlay wholesale: vault_get_character the Main first, modify that row's state, send it back complete. Maximums never belong in the overlay (they derive from the source; vault drops them). Rows in 'owned' (or legacy 'clone') mode have no overlay — edit the referenced character directly with vault_update_character instead. REQUIRES baseUpdatedAt: copy updatedAt from a fresh vault_get_character read of the MAIN character; a stale value is rejected with OUT_OF_SYNC and nothing is written.

ParametersJSON Schema
NameRequiredDescriptionDefault
idYesMongo `_id` of the Main character carrying the companion row.
stateYesThe row's complete replacement overlay. ATOMIC: what you send replaces the stored `state` wholesale — vault_get_character first, modify the returned row's `state`, and send it back complete. Stores current values only; maximums always derive from the source character and are dropped if sent.
companionIdYesThe companion ROW's `_id` from the Main character's `companions[]` array — NOT the buddy character's own `_id`.
baseUpdatedAtYesREQUIRED proof that you are working from the latest version: copy the `updatedAt` value verbatim from a FRESH read of this exact record (use the matching get tool first). Values from memory, from an earlier conversation, or guessed timestamps are rejected with OUT_OF_SYNC and nothing is written. After a successful update, the response carries the new `updatedAt` — use that for any follow-up write.

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.6/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare the safety profile (readOnly false, idempotent true, destructive false), and the description adds rich context beyond them: the source character is never written, maxes are dropped, the overlay replaces wholesale, and stale baseUpdatedAt is rejected with OUT_OF_SYNC writing nothing. The only small gap is it does not detail response shape, though an output schema exists.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Sentences are long and dense but front-load the core action, then layer the atomic-replace rule, the sibling alternative, and the baseUpdatedAt prerequisite in a logical order. Every sentence carries distinct operational meaning; slightly verbose for a description but justified by the complexity.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a nested, atomic write tool with 100% schema coverage and an output schema, this description covers the mutation semantics, the source-vs-overlay split, the sync-proof requirement, and the failure mode. An agent has everything needed to call it correctly without the schema.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, so the schema already documents the parameters and baseline would be 3. The description goes beyond it by explaining the read-modify-write pattern for `state`, that it is an atomic wholesale replacement, that maximums are dropped, and that `baseUpdatedAt` must be copied verbatim from a fresh read — meaningful semantics not derivable from the schema alone.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a precise verb and resource ('Write a LINK-mode companion row's transient overlay') and enumerates exactly which fields it covers (HP, temp HP, hit dice, death saves, exhaustion, stress, counters). It also explicitly distinguishes itself from vault_update_character for owned/clone rows, so an agent can differentiate it from siblings without opening either schema.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Gives explicit when-to-use (LINK-mode transient overlay for an unowned buddy), when-not-to-use ('Rows in owned or legacy clone mode have no overlay — edit the referenced character directly with vault_update_character instead'), and the required workflow (vault_get_character the Main first, modify, send back complete). Nothing is left to inference.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

vault_update_itemUpdate a vault itemA
Idempotent
Inspect

Patch fields on an existing user-authored item by id. Only supplied fields change. Use vault_search_items / vault_get_item to confirm the id first. REQUIRES baseUpdatedAt: copy updatedAt from a fresh vault_get_item read; a stale or fabricated value is rejected with OUT_OF_SYNC and nothing is written.

ParametersJSON Schema
NameRequiredDescriptionDefault
idYesMongo `_id` of the item to update.
oglNo
costNoCost in gold pieces (max 2 decimal places). Vault enforces non-negativity and precision.
nameNoDisplay name.
typeNoItem type. Free-form per ruleset; match the types the ruleset's catalog uses (vault_search_items shows them). Required at create.
usesNo
imageNo
activeNo
damageNo
effectNo
sourceNo
weightNo
_parentNoParent item ObjectId for variant items.
healingNo
masteryNoWeapon mastery name, for rulesets whose weapons carry one, as the ruleset's catalog names it.
rulesetNoRuleset code, from list_rulesets.
summaryNoShort one-line summary.
durationNo
rollModsNo
publisherNo
actionTypeNoAuthoring hint — when set, the character sheet's rule modal shows an 'Add to Actions' button that mints an action row with this `type`.
armorClassNoBase AC value the armor provides.
damageDiceNoBase damage expression (e.g. '1d8').
damageTypeNoDamage types as an array of strings (most items have one type; some have multiples).
diceFloorsNo
equipSlotsNoAllowed equip slot ids, from the ruleset's own slots (an existing item's equipSlots, via vault_get_item, shows them).
parametersNo
propertiesNo
ruleChoiceNo
weaponTypeNoWeapon category, as the ruleset's catalog names it (vault_search_items shows them).
descriptionNoFull item description. Markdown is supported.
resistancesNo
statBonusesNo
mechanicsKeyNo
spellChoicesNo
armorCategoryNoArmor category, as the ruleset's catalog names it (vault_search_items shows them).
baseUpdatedAtYesREQUIRED proof that you are working from the latest version: copy the `updatedAt` value verbatim from a FRESH read of this exact record (use the matching get tool first). Values from memory, from an earlier conversation, or guessed timestamps are rejected with OUT_OF_SYNC and nothing is written. After a successful update, the response carries the new `updatedAt` — use that for any follow-up write.
prerequisitesNo
forcedMovementNo
maxDexModifierNoCap on the DEX bonus this armor allows, from the item's source text.
preparedSpellsNo
abilityScoreSetNo
damageReductionNo
recurringDamageNo
abilityScoreBumpNo
diceReplacementsNo
spellListChoicesNo
prerequisitesLogicNo
proficiencyChoicesNo
stealthDisadvantageNo
strengthRequirementNo

Output Schema

ParametersJSON Schema
NameRequiredDescription
_idNo

TDQS

A4.4/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already cover safety (readOnlyHint=false, destructiveHint=false, idempotentHint=true), but the description adds real value beyond them: optimistic-concurrency enforcement, that no fields not supplied are touched, and that a failed write is a no-op. It stops short of describing other mutation behaviors (e.g. validation of nested payloads, permission requirements) but the concurrency contract is the important one.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Three sentences, front-loaded with the action, then the read-first routing, then the hard requirement and its failure mode. No filler and no repetition of annotation or schema content.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a high-complexity mutation with an output schema already documenting the new `updatedAt`, the description supplies the critical missing contract (fresh-read token) and leaves field shape to vault_get_item as it explicitly instructs. Reasonably complete, though it could say more about which fields are patchable vs immutable.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is only 35% across 51 parameters, so the description would ideally compensate. It richly documents baseUpdatedAt's verbatim-copy requirement and scopes `id`, but gives no guidance for the ~49 other optional nested fields; those must be inferred from property names, enums, and a vault_get_item read. Baseline 3 fits the partial compensation.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

Specific verb + resource + scope: 'Patch fields on an existing user-authored item by id. Only supplied fields change.' It also distinguishes the tool from the read siblings it names (vault_search_items / vault_get_item), so an agent can tell what this does without opening the schema.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explicit preconditions and route: confirm the id with vault_search_items / vault_get_item first, and baseUpdatedAt must come from a fresh read of this exact record. It also names the failure mode (OUT_OF_SYNC, nothing written), which is exactly the guidance needed to use it correctly.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

vault_update_ruleUpdate a vault ruleA
Idempotent
Inspect

Patch fields on an existing user-authored rule by id. Only the fields you supply are changed; everything else is preserved. Use vault_search_rules / vault_get_rule first to confirm the id and current state. REQUIRES baseUpdatedAt: copy updatedAt from a fresh vault_get_rule read; a stale or fabricated value is rejected with OUT_OF_SYNC and nothing is written.

ParametersJSON Schema
NameRequiredDescriptionDefault
idYesMongo `_id` of the rule to update.
ageNo
oglNo
featNoMongo `_id` reference (24-character hex string).
nameNoDisplay name of the rule.
sizeNo
typeNoRule category. Required at create time; vault rejects without it.
usesNo
imageNo
rangeNoHow far the ability reaches when invoked: `kind`, plus `distance` and its `unit` for a kind that takes a distance. Absent: the rule authoring guide (vault_get_authoring_guide, entityType 'rule') gives the default.
speedNo
activeNo
damageNo
effectNo
hitDieNo
sourceNo
_parentNoMongo `_id` reference (24-character hex string).
actionsNoAction-cost marker, for rulesets whose rules carry one; the value is the source text.
healingNo
rulesetNoRuleset code, from list_rulesets.
summaryNoShort one-line summary.
durationNo
featOpenNo
keywordsNo
rollModsNo
abilitiesNo
languagesNo
publisherNo
actionTypeNoAuthoring hint — when set, the character sheet's rule modal shows an 'Add to Actions' button that mints an action row with this `type`.
categoriesNo
diceFloorsNo
parametersNo
repeatableNoA rule that may be taken/granted more than once, each time as a distinct instance with its own sub-choices — a repeatable feat, or a class ability its class grants at several levels.
ruleChoiceNo
descriptionNoFull rule body. Markdown is supported.
resistancesNo
statBonusesNo
toolChoicesNo
creatureTypeNo
mechanicsKeyNo
savingThrowsNo
skillChoicesNo
spellChoicesNo
abilityScoresNo
actionEconomyNoWhat invoking the ability costs on a turn. The rule authoring guide (vault_get_authoring_guide, entityType 'rule') gives the absent default. Distinct from the mechanics actionType (a kind-of-action label).
armorTrainingNo
baseUpdatedAtYesREQUIRED proof that you are working from the latest version: copy the `updatedAt` value verbatim from a FRESH read of this exact record (use the matching get tool first). Values from memory, from an earlier conversation, or guessed timestamps are rejected with OUT_OF_SYNC and nothing is written. After a successful update, the response carries the new `updatedAt` — use that for any follow-up write.
multiclassingNoWhat multiclassing INTO this class grants (weapon/armor lists apply fixed; skillChoices/toolChoices render pickers). Absent = no multiclass proficiencies.
prerequisitesNo
castingAbilityNoThe ability this rule's spellcasting keys off. Author it on a class's Spellcasting ability rule; vault's creation and level-up wizards write it to the character-wide Spellcasting Ability (first-wins, never overwriting), and a multiclass whose ability differs stamps its granted spells per-entry. Distinct from a spell block's castingAbility, which overrides per grant. Absent = the rule says nothing about the character's casting ability.
forcedMovementNo
preparedSpellsNo
spellAbilitiesNo
abilityScoreSetNo
damageReductionNo
recurringDamageNo
abilityScoreBumpNo
diceReplacementsNo
levelProgressionNo
spellListChoicesNo
casterProgressionNoHow this class contributes to the combined multiclass spell-slot pool; the engine applies each progression's rule. Authorable on a base class or a subclass (a subclass that grants the casting carries it). Absent = non-caster.
startingEquipmentNo
toolProficienciesNo
prerequisitesLogicNo
proficiencyChoicesNo
skillProficienciesNo
weaponProficienciesNo
defaultAbilityScoresNo

Output Schema

ParametersJSON Schema
NameRequiredDescription
_idNo

TDQS

A4.4/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already mark this non-readOnly but idempotent and non-destructive; the description goes well beyond by disclosing patch semantics (only supplied fields change, everything else preserved) and optimistic-concurrency behavior (stale baseUpdatedAt is rejected with OUT_OF_SYNC and nothing is written).

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Four sentences, front-loaded with the core action, each earning its place: patch scope, preservation guarantee, read-first guidance, and the concurrency requirement. No filler.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a large mutation tool with annotations and an output schema (so return values need not be explained), the description covers partial-update semantics and the OUT_OF_SYNC failure mode. It omits any note on permissions/auth scope, which is the only notable gap.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is only 25% across 68 params, and the description explains the semantics of the parameter set as a whole (partial update; baseUpdatedAt must be copied from a fresh read or the write fails). That is genuinely useful, but it does not compensate for the many undocumented fields, so it lands at the baseline-plus level.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb (Patch) plus resource (user-authored rule) plus scope (by id with partial-field semantics), which cleanly distinguishes it from vault_create_rule, vault_delete_rule, and the sibling vault_update_item/spell tools.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explicitly routes the agent to vault_search_rules / vault_get_rule to confirm the id and current state before updating, and states the required baseUpdatedAt prerequisite. It stops short of naming when NOT to use it (e.g., create vs update), so 4 rather than 5.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

vault_update_spellUpdate a vault spellA
Idempotent
Inspect

Patch fields on an existing user-authored spell by id. Only supplied fields change. Use vault_search_spells / vault_get_spell to confirm the id first. REQUIRES baseUpdatedAt: copy updatedAt from a fresh vault_get_spell read; a stale or fabricated value is rejected with OUT_OF_SYNC and nothing is written.

ParametersJSON Schema
NameRequiredDescriptionDefault
idYesMongo `_id` of the spell to update.
oglNo
areaNoArea of effect. `shape`; `size` (ft); `width` for a line.
nameNoDisplay name.
rankNoRank, for rulesets whose spells carry one. Free-form.
typeNoSpell type (the ruleset's name for a spell). Required at create.
usesNo
levelNoSpell level, within the schema's range. The spell authoring guide gives the convention.
rangeNoRange. `kind`; `distance` and its `unit` for a ranged spell (absent unit = feet).
activeNo
damageNo
effectNo
ritualNoRitual tag: the spell can be cast as a ritual.
schoolNoSpell school name.
sourceNo
_parentNoParent spell ObjectId for variant spells.
actionsNoAction-cost marker, for rulesets whose spells carry one; the value is the source text.
classesNoClass-membership list for rulesets whose spells do not use `categories` (the spell authoring guide covers `categories`). Free-form per ruleset.
healingNo
rulesetNoRuleset code, from list_rulesets.
summaryNoShort one-line summary.
durationNoSpell duration. `unit`; `count` for a timed unit; concentration flag; upTo flag for a non-concentration capped duration ("Up to 1 minute").
rollModsNo
publisherNo
actionTypeNoAuthoring hint — when set, the character sheet's rule modal shows an 'Add to Actions' button that mints an action row with this `type`.
categoriesNoGo-forward class membership. The field `spellChoices[].allowedCategories` filters on; the vault UI labels it 'Class(es)'. Free-form, taggable.
componentsNoComponents: verbal/somatic/material flags, plus material text, gp cost, and consumed flag.
diceFloorsNo
parametersNo
ruleChoiceNo
castingTimeNoCasting time. `unit`, plus `count` for a timed unit.
descriptionNoFull spell body. Markdown is supported.
higherLevelNoScaling text: what changes when the spell is cast at a higher level or scales with the caster, source text.
resistancesNo
statBonusesNo
mechanicsKeyNo
spellChoicesNo
baseUpdatedAtYesREQUIRED proof that you are working from the latest version: copy the `updatedAt` value verbatim from a FRESH read of this exact record (use the matching get tool first). Values from memory, from an earlier conversation, or guessed timestamps are rejected with OUT_OF_SYNC and nothing is written. After a successful update, the response carries the new `updatedAt` — use that for any follow-up write.
prerequisitesNo
forcedMovementNo
preparedSpellsNo
abilityScoreSetNo
damageReductionNo
reactionTriggerNoFor a casting time taken in response to a trigger, the trigger text, source text.
recurringDamageNo
abilityScoreBumpNo
diceReplacementsNo
spellListChoicesNo
prerequisitesLogicNo
proficiencyChoicesNo

Output Schema

ParametersJSON Schema
NameRequiredDescription
_idNo

TDQS

A4.2/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint=false, destructiveHint=false, idempotentHint=true, and openWorldHint=false, so the mutation/safety profile is covered. The description adds real behavioral context beyond that: only-supplied-fields semantics, an optimistic-concurrency token requirement, and the OUT_OF_SYNC rejection with 'nothing is written' failure behavior.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Four tightly packed sentences, front-loaded with the core purpose, then the patch rule, the id-discovery step, and finally the critical precondition. No filler; the emphasis on REQUIRES is warranted.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a 50-property mutation with an output schema (so return format needn't be explained), the description supplies the essential guidance: purpose, patch semantics, id lookup, and the concurrency token. It is nearly complete, only omitting any coverage of the many optional field parameters.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is only 46% across 50 parameters. The description covers the two required params well (id must be confirmed; baseUpdatedAt must be a fresh verbatim copy) with rejection semantics, but it adds nothing for the remaining patch fields beyond what the schema already says, so it only partially compensates for the coverage gap.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb (patch) and resource (existing user-authored spell by id), and sharpens it with 'Only supplied fields change,' which describes PATCH-style partial-update semantics. This cleanly separates it from vault_create_spell and vault_update_rule among the many siblings.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Routes the agent to vault_search_spells / vault_get_spell to confirm the id first, and states the baseUpdatedAt precondition explicitly. Clear operational context, though it doesn't explicitly contrast update against create/delete for the same resource.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

whoamiWho am IA
Read-onlyIdempotent
Inspect

Returns the Embers user identity and OAuth scopes the connected client is authorized for.

ParametersJSON Schema
NameRequiredDescriptionDefault

No parameters

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.5/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint=true, idempotentHint=true, and destructiveHint=false, which cover the safe, side-effect-free nature. The description adds meaningful behavioral context by specifying that the returned scopes are specifically those the connected client is authorized for, which is not in the annotations.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

A single, well-structured sentence delivers the complete purpose with no filler. Key information is front-loaded, and every word contributes value.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a parameterless, read-only identity/scope lookup with an output schema and comprehensive annotations, the description is complete. It tells the agent what the tool returns and leaves the detailed return structure to the output schema.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The tool has zero parameters and an empty input schema, so parameter semantics are trivially satisfied. The description does not need to document parameters and correctly focuses on the output.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

Description states a specific verb ('Returns') and resource ('Embers user identity and OAuth scopes'), making the tool's purpose immediately clear. It also distinguishes this introspection tool from all sibling tools, none of which overlap with identity/scope retrieval.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description clearly implies the use case: checking who the connected client is and which OAuth scopes it has. There are no sibling alternatives for this purpose, and no additional exclusions are needed for such a simple, parameterless introspection tool.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

  1. 2 tool updates
    • Changedvault_create_character1 field changed
      • addedInput schema / properties / offense / properties / spellCasting / properties / bonuses
        Added value: +{
        +  "description": "The character's Misc bonuses on the spell / feature attack bonus and save DC (the sheet's Spellcasting section). The array is written whole: send every row to keep.",
        +  "items": {
        +    "additionalProperties": {},
        +    "properties": {
        +      "bonus": {
        +        "description": "Flat bonus the row adds.",
        +        "type": "number"
        +      },
        +      "description": {
        +        "description": "What the bonus is (an item, a feature, a house rule).",
        +        "type": "string"
        +      },
        +      "saveDc": {
        +        "description": "Adds to the spell / feature save DC. Defaults to false.",
        +        "type": "boolean"
        +      },
        +      "toHit": {
        +        "description": "Adds to the spell / feature attack bonus. Defaults to true.",
        +        "type": "boolean"
        +      }
        +    },
        +    "type": "object"
        +  },
        +  "type": "array"
        +}
    • Changedvault_update_character1 field changed
      • addedInput schema / properties / offense / properties / spellCasting / properties / bonuses
        Added value: +{
        +  "description": "The character's Misc bonuses on the spell / feature attack bonus and save DC (the sheet's Spellcasting section). The array is written whole: send every row to keep.",
        +  "items": {
        +    "additionalProperties": {},
        +    "properties": {
        +      "bonus": {
        +        "description": "Flat bonus the row adds.",
        +        "type": "number"
        +      },
        +      "description": {
        +        "description": "What the bonus is (an item, a feature, a house rule).",
        +        "type": "string"
        +      },
        +      "saveDc": {
        +        "description": "Adds to the spell / feature save DC. Defaults to false.",
        +        "type": "boolean"
        +      },
        +      "toHit": {
        +        "description": "Adds to the spell / feature attack bonus. Defaults to true.",
        +        "type": "boolean"
        +      }
        +    },
        +    "type": "object"
        +  },
        +  "type": "array"
        +}
  2. 34 tool updates
    • Changedimagine_update_adventure1 field changed
      • changedInput schema / properties / ruleset / description
        Previous value: -"Ruleset code (e.g. '5th Edition', '5e24', 'PFRPG'). Required at create."New value: +"Ruleset code, from list_rulesets. Required at create."
    • Changedplay_add_campaign_item2 fields changed
      • removedInput schema / properties / ruleset / enum
        Removed value: -[
        -  "5th Edition",
        -  "5e24",
        -  "PFRPG",
        -  "PFRPG2",
        -  "PF Playtest",
        -  "Savage Worlds",
        -  "Savage Embers",
        -  "Solarian Conflict",
        -  "Embers RPG",
        -  "Universal",
        -  "Fate Core",
        -  "Fate Accelerated"
        -]
      • addedInput schema / properties / ruleset / minLength
        Added value: +1
    • Changedplay_add_campaign_leg3 fields changed
      • changedInput schema / properties / ruleset / description
        Previous value: -"Ruleset for the new leg. Required. One leg per ruleset — play answers 409 if the campaign already has a leg for this ruleset."New value: +"Ruleset code for the new leg; list_rulesets returns the codes this account can use. Required. One leg per ruleset — play answers 409 if the campaign already has a leg for this ruleset, 400 for an unknown code, and 403 for a ruleset this account is not entitled to."
      • removedInput schema / properties / ruleset / enum
        Removed value: -[
        -  "5th Edition",
        -  "5e24",
        -  "PFRPG",
        -  "PFRPG2",
        -  "PF Playtest",
        -  "Savage Worlds",
        -  "Savage Embers",
        -  "Solarian Conflict",
        -  "Embers RPG",
        -  "Universal",
        -  "Fate Core",
        -  "Fate Accelerated"
        -]
      • addedInput schema / properties / ruleset / minLength
        Added value: +1
    • Changedplay_add_campaign_rule2 fields changed
      • removedInput schema / properties / ruleset / enum
        Removed value: -[
        -  "5th Edition",
        -  "5e24",
        -  "PFRPG",
        -  "PFRPG2",
        -  "PF Playtest",
        -  "Savage Worlds",
        -  "Savage Embers",
        -  "Solarian Conflict",
        -  "Embers RPG",
        -  "Universal",
        -  "Fate Core",
        -  "Fate Accelerated"
        -]
      • addedInput schema / properties / ruleset / minLength
        Added value: +1
    • Changedplay_add_campaign_spell2 fields changed
      • removedInput schema / properties / ruleset / enum
        Removed value: -[
        -  "5th Edition",
        -  "5e24",
        -  "PFRPG",
        -  "PFRPG2",
        -  "PF Playtest",
        -  "Savage Worlds",
        -  "Savage Embers",
        -  "Solarian Conflict",
        -  "Embers RPG",
        -  "Universal",
        -  "Fate Core",
        -  "Fate Accelerated"
        -]
      • addedInput schema / properties / ruleset / minLength
        Added value: +1
    • Changedplay_create_campaign3 fields changed
      • changedInput schema / properties / ruleset / description
        Previous value: -"Ruleset code (e.g. '5th Edition', '5e24', 'PFRPG', 'Savage Worlds'). Becomes the campaign's first leg. Play enforces required on the backend; the gateway lets it be omitted so the LLM gets a clean backend error if it forgets."New value: +"Ruleset code; list_rulesets returns the codes this account can use. Becomes the campaign's first leg. Play enforces required and a known code on the backend (400) and answers 403 for a ruleset this account is not entitled to; the gateway lets it be omitted so the LLM gets a clean backend error if it forgets."
      • removedInput schema / properties / ruleset / enum
        Removed value: -[
        -  "5th Edition",
        -  "5e24",
        -  "PFRPG",
        -  "PFRPG2",
        -  "PF Playtest",
        -  "Savage Worlds",
        -  "Savage Embers",
        -  "Solarian Conflict",
        -  "Embers RPG",
        -  "Universal",
        -  "Fate Core",
        -  "Fate Accelerated"
        -]
      • addedInput schema / properties / ruleset / minLength
        Added value: +1
    • Changedplay_list_campaign_items2 fields changed
      • removedInput schema / properties / ruleset / enum
        Removed value: -[
        -  "5th Edition",
        -  "5e24",
        -  "PFRPG",
        -  "PFRPG2",
        -  "PF Playtest",
        -  "Savage Worlds",
        -  "Savage Embers",
        -  "Solarian Conflict",
        -  "Embers RPG",
        -  "Universal",
        -  "Fate Core",
        -  "Fate Accelerated"
        -]
      • addedInput schema / properties / ruleset / minLength
        Added value: +1
    • Changedplay_list_campaign_rules2 fields changed
      • removedInput schema / properties / ruleset / enum
        Removed value: -[
        -  "5th Edition",
        -  "5e24",
        -  "PFRPG",
        -  "PFRPG2",
        -  "PF Playtest",
        -  "Savage Worlds",
        -  "Savage Embers",
        -  "Solarian Conflict",
        -  "Embers RPG",
        -  "Universal",
        -  "Fate Core",
        -  "Fate Accelerated"
        -]
      • addedInput schema / properties / ruleset / minLength
        Added value: +1
    • Changedplay_list_campaign_spells2 fields changed
      • removedInput schema / properties / ruleset / enum
        Removed value: -[
        -  "5th Edition",
        -  "5e24",
        -  "PFRPG",
        -  "PFRPG2",
        -  "PF Playtest",
        -  "Savage Worlds",
        -  "Savage Embers",
        -  "Solarian Conflict",
        -  "Embers RPG",
        -  "Universal",
        -  "Fate Core",
        -  "Fate Accelerated"
        -]
      • addedInput schema / properties / ruleset / minLength
        Added value: +1
    • Changedplay_remove_campaign_item2 fields changed
      • removedInput schema / properties / ruleset / enum
        Removed value: -[
        -  "5th Edition",
        -  "5e24",
        -  "PFRPG",
        -  "PFRPG2",
        -  "PF Playtest",
        -  "Savage Worlds",
        -  "Savage Embers",
        -  "Solarian Conflict",
        -  "Embers RPG",
        -  "Universal",
        -  "Fate Core",
        -  "Fate Accelerated"
        -]
      • addedInput schema / properties / ruleset / minLength
        Added value: +1
    • Changedplay_remove_campaign_rule2 fields changed
      • removedInput schema / properties / ruleset / enum
        Removed value: -[
        -  "5th Edition",
        -  "5e24",
        -  "PFRPG",
        -  "PFRPG2",
        -  "PF Playtest",
        -  "Savage Worlds",
        -  "Savage Embers",
        -  "Solarian Conflict",
        -  "Embers RPG",
        -  "Universal",
        -  "Fate Core",
        -  "Fate Accelerated"
        -]
      • addedInput schema / properties / ruleset / minLength
        Added value: +1
    • Changedplay_remove_campaign_spell2 fields changed
      • removedInput schema / properties / ruleset / enum
        Removed value: -[
        -  "5th Edition",
        -  "5e24",
        -  "PFRPG",
        -  "PFRPG2",
        -  "PF Playtest",
        -  "Savage Worlds",
        -  "Savage Embers",
        -  "Solarian Conflict",
        -  "Embers RPG",
        -  "Universal",
        -  "Fate Core",
        -  "Fate Accelerated"
        -]
      • addedInput schema / properties / ruleset / minLength
        Added value: +1
    • Changedplay_set_campaign_leg_active2 fields changed
      • removedInput schema / properties / ruleset / enum
        Removed value: -[
        -  "5th Edition",
        -  "5e24",
        -  "PFRPG",
        -  "PFRPG2",
        -  "PF Playtest",
        -  "Savage Worlds",
        -  "Savage Embers",
        -  "Solarian Conflict",
        -  "Embers RPG",
        -  "Universal",
        -  "Fate Core",
        -  "Fate Accelerated"
        -]
      • addedInput schema / properties / ruleset / minLength
        Added value: +1
    • Changedvault_build_monster30 fields changed
      • changedInput schema / properties / abilities / description
        Previous value: -"Six ability scores as numbers. Gateway computes modifiers, attack/damage/save/skill/initiative derivations."New value: +"Ability scores as numbers, one per ability score key. Vault computes modifiers, attack/damage/save/skill/initiative derivations."
      • changedInput schema / properties / ac / description
        Previous value: -"AC block. `total` is the value the sheet should display (source-text value, like '16'). Gateway computes the stored base by subtracting DEX modifier (with medium/heavy armor weight caps) and any shield/magic/misc bonuses. Per the guide Rule 1."New value: +"AC block. `total` is the value the sheet should display (the source-text number). Vault computes the stored base from it, the `armorWeight` given, and any shield/magic/misc bonuses, per the guide Rule 1."
      • changedInput schema / properties / actions / description
        Previous value: -"Action entries. `type` per the guide Rule 3 (Melee / Range / Special / Reaction / Legendary / Bonus). For attacks, pass `attackBonus` + `attackAttribute` + `damageDice` + `damageType` + `damageAttribute`; gateway back-derives `attack.misc`. For ranged spell attacks (Hurl Flame etc.) use the spellcasting attribute, not strength/dexterity. `recharge: '5-6'` (or '6', '4-6') creates a matching trackables[] checkbox the sheet renders as a cooldown."New value: +"Action entries. `type` per the guide Rule 3. For attacks, pass `attackBonus` + `attackAttribute` + `damageDice` + `damageType` + `damageAttribute`; vault back-derives `attack.misc`. The guide Rule 3 gives `attackAttribute` for a spell attack. `recharge` takes the source's recharge text and creates a matching trackables[] checkbox the sheet renders as a cooldown; the guide gives the form."
      • changedInput schema / properties / actions / items / properties / type / enum
        Previous value: -[
        -  "Melee",
        -  "Range",
        -  "Special",
        -  "Reaction",
        -  "Legendary",
        -  "Bonus"
        -]New value: +[
        +  "Melee",
        +  "Range",
        +  "Special",
        +  "Bonus",
        +  "Reaction",
        +  "Legendary",
        +  "Lair"
        +]
      • changedInput schema / properties / additionalNotes / description
        Previous value: -"Any free-form notes[] entries the LLM wants to author beyond the auto-generated Challenge / Legendary Actions / Speed-alternate-form rows. Use sparingly — most stat-block content has a dedicated structured field above."New value: +"Any free-form notes[] entries the LLM wants to author beyond the auto-generated challenge, legendary-intro, and alternate-form speed rows. Use sparingly — most stat-block content has a dedicated structured field above."
      • changedInput schema / properties / alignment / description
        Previous value: -"Alignment text, e.g. 'Unaligned' or 'Neutral Evil'."New value: +"Alignment text, source-exact."
      • changedInput schema / properties / conditionImmunities / description
        Previous value: -"5e split form: condition-only immunities. Use only if the source says 'Condition Immunities' as a separate row."New value: +"Split form: condition-only immunities, source-exact. Use only if the source has a separate condition immunities row."
      • changedInput schema / properties / cr / description
        Previous value: -"Challenge Rating. Must be one of the canonical 5e24 values: 0, 0.125 (CR 1/8), 0.25 (CR 1/4), 0.5 (CR 1/2), or any integer 1-30. Gateway looks up XP reward + level-equivalent XP + proficiency bonus."New value: +"Challenge Rating as a number, a fraction as its decimal (e.g. 0.125 for CR 1/8); vault answers an error for a value that is not a challenge rating. Vault looks up XP reward + level-equivalent XP + proficiency bonus."
      • changedInput schema / properties / creatureType / description
        Previous value: -"Creature type — source text, e.g. 'Elemental', 'Humanoid', 'Dragon (Chromatic)'. Preserved verbatim into `core.race` per the guide Rule 16 'preserve original text'."New value: +"Creature type, source text. Preserved verbatim into `core.race` per the guide Rule 16 'preserve original text'."
      • changedInput schema / properties / damageImmunities / description
        Previous value: -"5e (2014) split form: damage-only immunities. Use only if the source says 'Damage Immunities' as a separate row."New value: +"Split form: damage-only immunities, source-exact. Use only if the source has a separate damage immunities row."
      • changedInput schema / properties / damageResistances / description
        Previous value: -"5e split form: damage-only resistances. Use only if the source says 'Damage Resistances'."New value: +"Split form: damage-only resistances, source-exact. Use only if the source has a separate damage resistances row."
      • changedInput schema / properties / damageVulnerabilities / description
        Previous value: -"5e split form: damage-only vulnerabilities."New value: +"Split form: damage-only vulnerabilities, source-exact."
      • changedInput schema / properties / gear / description
        Previous value: -"Gear listed on the stat block ('Greatsword, Splint Armor'). Each becomes an items[] entry with `equipped: false` (monsters don't use equip slots) per Rule 19. Server-side template fill adds the four currency items separately."New value: +"Gear listed on the stat block, source text. Each becomes an items[] entry with `equipped: false` (monsters don't use equip slots) per Rule 19. Server-side template fill adds the currency items separately."
      • changedInput schema / properties / hitDiceSize / description
        Previous value: -"Hit-die size mapped from creature size per 5e24 MM: Tiny d4, Small d6, Medium d8, Large d10, Huge d12, Gargantuan d20. Defaults to d8 when omitted (Medium creatures, by far the common case)."New value: +"Hit-die size from the stat block. Omitted, the app chooses the die."
      • changedInput schema / properties / hitDiceSize / enum
        Previous value: -[
        -  "d4",
        -  "d6",
        -  "d8",
        -  "d10",
        -  "d12",
        -  "d20"
        -]New value: +[
        +  "d4",
        +  "d6",
        +  "d8",
        +  "d10",
        +  "d12",
        +  "d20",
        +  "d100"
        +]
      • changedInput schema / properties / immunities / description
        Previous value: -"5e24 combined Immunities text (damage + condition, semicolon-separated): 'Fire, Poison; Frightened, Poisoned'. Use this when the source says 'Immunities'."New value: +"Combined immunities row, source-exact, damage and condition entries as the source writes them. Use this when the source has one combined immunities row."
      • changedInput schema / properties / initiativeBonus / description
        Previous value: -"Override the initiative bonus only if the listed value differs from the DEX modifier. Per the guide Rule 17, gateway sets `offense.initiative.misc = listed − DEX-mod`."New value: +"The listed initiative bonus. Pass it only if it differs from the bonus the sheet derives; vault keeps the difference in `offense.initiative.misc` per the guide Rule 17."
      • changedInput schema / properties / languages / description
        Previous value: -"Languages text, source-exact (e.g. '—' or 'Common, Draconic, telepathy 60 ft.'). Stored in `core.languages`."New value: +"Languages text, source-exact. Stored in `core.languages`."
      • changedInput schema / properties / legendaryIntro / description
        Previous value: -"Legendary Actions intro paragraph (the prose about how legendary actions work for this creature). Per the guide Rule 8, lands in notes[] under name 'Legendary Actions'. Individual legendary action entries go in `actions[]` with `type: 'Legendary'`."New value: +"Intro paragraph of the stat block's legendary section (the prose about how those actions work for this creature). Lands in notes[] under the name the guide Rule 8 gives. Individual legendary entries go in `actions[]` with the matching `type`."
      • removedInput schema / properties / ruleset / const
        Removed value: -"5e24"
      • changedInput schema / properties / ruleset / description
        Previous value: -"Only '5e24' is supported. The authoring guide and the conversion math are 5e24-specific; other rulesets will land via their own build tools."New value: +"A ruleset the monster builder supports. The authoring guide and the conversion math are ruleset-specific; other rulesets will land via their own build tools."
      • addedInput schema / properties / ruleset / enum
        Added value: +[
        +  "5e24"
        +]
      • changedInput schema / properties / saves / description
        Previous value: -"Saving throw bonuses for the proficient ones only. Gateway derives `attributes[].proficient = true` and a `misc` adjustment so the sheet's `ability + PB + misc` lands on the source bonus."New value: +"Saving throw bonuses for the proficient ones only. Vault derives `attributes[].proficient = true` and a `misc` adjustment so the sheet total lands on the source bonus."
      • changedInput schema / properties / senses / description
        Previous value: -"Senses other than passive perception: darkvision, blindsight, tremorsense, truesight. Each becomes a rules[] Ability entry with `name` ('Darkvision') and `detail` ('120 ft.'). Passive Perception is NOT authored — sheet derives it from the Perception skill."New value: +"The stat block's senses other than the passive one the sheet derives, each as `name` and `detail` (the source text after the name). Each becomes a rules[] entry. The monster authoring guide covers which senses to author."
      • changedInput schema / properties / size / description
        Previous value: -"Size text — single value ('Medium') or variable form ('Medium or Small') per the guide Rule 18. Stored verbatim in `core.size`."New value: +"Size text, source-exact: a single value or the variable form ('X or Y') per the guide Rule 18. Stored verbatim in `core.size`."
      • changedInput schema / properties / skills / description
        Previous value: -"Skill bonuses for proficient / expertise skills only. Gateway derives the proficient + expertise flags + misc so the sheet total matches the source bonus per the guide Rule 6."New value: +"Skill bonuses for proficient / expertise skills only. Vault derives the proficient + expertise flags + misc so the sheet total matches the source bonus per the guide Rule 6."
      • changedInput schema / properties / sourceProficiencyBonus / description
        Previous value: -"Override the PB derived from CR. Use only when the source stat block explicitly lists a non-standard PB (e.g. a CR-low legendary creature with PB +5). For PB +7 and above the high-PB misc compensation per the guide Rule 15 kicks in automatically."New value: +"Override the PB derived from CR. Use only when the source stat block explicitly lists a PB other than the one its CR gives. A PB larger than the sheet's keeps the difference in misc automatically, per the guide Rule 15."
      • changedInput schema / properties / speed / description
        Previous value: -"Speed block. `walk` is the base walking speed in feet. Non-walking modes (climb / fly / swim / burrow) become rules[] Ability entries with the listed range. `alternateForm` carries the parenthetical text from lycanthrope-style stat blocks ('40 ft. in boar form') per the guide Rule 5; lands in notes[]."New value: +"Speed block, in feet. `walk` is the base walking speed; the other modes become rules[] entries with the listed range. `alternateForm` carries a stat block's parenthetical alternate-form speed text, source-exact, per the guide Rule 5; lands in notes[]."
      • changedInput schema / properties / spellcasting / description
        Previous value: -"Innate spellcasting block per the guide Rule 4. Gateway formats the spell list as markdown with two-space hard breaks between frequency rows and italic spell names: `**At will:** *detect evil and good*  \\n**1/day each:** *commune*, *raise dead*`. Lands as a single rules[] Ability entry named 'Innate Spellcasting'."New value: +"Innate spellcasting block per the guide Rule 4: the casting ability, save DC, and the spells grouped by their source frequency text. Vault formats the spell list as markdown per that rule and lands it as a single rules[] entry."
      • changedInput schema / properties / traits / description
        Previous value: -"Trait entries (Web-Dweller, Molten Body, Pack Tactics, etc.). Use `summary` for parenthetical usage limits per Rule 14 (e.g. 'Legendary Resistance' name + '3/Day, or 4/Day in Lair' summary + body description). Use `detail` for the kind of short qualifier on entries like Darkvision (but darkvision itself goes under `senses`)."New value: +"Trait entries, source text. Use `summary` for a parenthetical usage limit per the guide Rule 14, and `detail` for a short qualifier per Rule 17; senses go under `senses`."
    • Changedvault_build_pc20 fields changed
      • changedInput schema / properties / abilityBumpPicks / description
        Previous value: -"Ability-score-increase picks for any applied rule carrying an `abilityScoreBump` (a feat / ability that raises a score by your choice — e.g. an ASI). Key is the granting rule `_id`; value is `{ option, lines }`: `option` is the 0-based index of the chosen alternative in that bump's `options` (the player picks exactly ONE — the OR), and `lines` is parallel to that option's `lines`, each entry the lowercase ability names assigned to that line (the AND). Each line needs exactly its `count` distinct abilities drawn from its `eligible` pool (empty = any of the six), none exceeding its `max`. The build bakes the increases onto the ability scores before HP, so a Constitution increase feeds level-1 HP. A `repeatable` feat filling the background slot keys `bg:<featId>` instead of `<featId>`."New value: +"Ability-score-increase picks for any applied rule carrying an `abilityScoreBump` (a feat / ability that raises a score by your choice). Key is the granting rule `_id`; value is `{ option, lines }`: `option` is the 0-based index of the chosen alternative in that bump's `options` (the player picks exactly ONE — the OR), and `lines` is parallel to that option's `lines`, each entry the lowercase ability names assigned to that line (the AND). Each line needs exactly its `count` distinct abilities drawn from its `eligible` pool (empty = any ability in the schema's abilities list), none exceeding its `max`. The build bakes the increases onto the ability scores before it derives the rest of the sheet. A `repeatable` feat filling the background slot keys `bg:<featId>` instead of `<featId>`."
      • changedInput schema / properties / abilityChoices / description
        Previous value: -"Picks for a class ability's `choice` (ruleChoice). Key is the ability rule `_id`; value is exactly `choice.count` picked option `_id`s from `choice.options`. Each option carries a `type`. When a picked option carries its OWN sub-choices (any type — an Ability like a Cleric's Divine Order → Thaumaturge, or a Feat granted 'of your choice'), supply them in `proficiencyChoicePicks` / `spellChoicePicks` / `spellListChoicePicks` / `preparedSpellPicks` keyed by the picked option's `_id`, just like the background feat."New value: +"Picks for a class ability's `choice` (ruleChoice). Key is the ability rule `_id`; value is exactly `choice.count` picked option `_id`s from `choice.options`. Each option carries a `type`. When a picked option carries its OWN sub-choices (any type — an Ability or a Feat), supply them in `proficiencyChoicePicks` / `spellChoicePicks` / `spellListChoicePicks` / `preparedSpellPicks` keyed by the picked option's `_id`, just like the background feat."
      • changedInput schema / properties / abilityScoreAssignments / description
        Previous value: -"Final ability scores by key, all six required. Must satisfy the chosen `abilityScoreMethod`: standard-array uses [15,14,13,12,10,8] in any order; point-buy each in 8..15 within the budget; class-array is taken from the class's defaultAbilityScores (still send the six values you intend)."New value: +"Final ability scores by ability key, every key required. Must satisfy the chosen `abilityScoreMethod` as `constants.abilityScoreMethods` describes it (still send every value you intend)."
      • changedInput schema / properties / abilityScorePointBudget / description
        Previous value: -"Point-buy budget override. Defaults to 27 (5e24). Only used for `abilityScoreMethod: 'point-buy'`."New value: +"Budget override for an ability-score method that spends a budget. Defaults to that method's budget in `constants.abilityScoreMethods`. Ignored for a method without one."
      • changedInput schema / properties / alignment / enum
        Previous value: -[
        -  "Lawful Good",
        -  "Neutral Good",
        -  "Chaotic Good",
        -  "Lawful Neutral",
        -  "Neutral",
        -  "Chaotic Neutral",
        -  "Lawful Evil",
        -  "Neutral Evil",
        -  "Chaotic Evil"
        -]New value: +[
        +  "Lawful Good",
        +  "Lawful Neutral",
        +  "Lawful Evil",
        +  "Neutral Good",
        +  "Neutral",
        +  "Neutral Evil",
        +  "Chaotic Good",
        +  "Chaotic Neutral",
        +  "Chaotic Evil"
        +]
      • changedInput schema / properties / backgroundBumpAssignments / description
        Previous value: -"Background ability-score bump per key. 'twoOne' mode: one ability +2 and a different one +1. 'oneOneOne' mode: three different abilities +1. Keys not bumped are omitted or 0. Only the background's `abilityScores` keys are eligible."New value: +"Background ability-score bump per key, as `backgroundBumpMode` distributes it (each mode's amounts are the wizard constants' `backgroundBumpModeOptions`, from `vault_get_pc_creation_options` kind `constants`). Keys not bumped are omitted or 0. Only the background's `abilityScores` keys are eligible."
      • changedInput schema / properties / backgroundBumpMode / description
        Previous value: -"Required when the background grants an ability bump. 'twoOne' = +2/+1; 'oneOneOne' = +1/+1/+1."New value: +"Required when the background grants an ability bump; each mode's amounts are the wizard constants' `backgroundBumpModeOptions`."
      • changedInput schema / properties / backgroundFeatRuleId / description
        Previous value: -"The background's Origin feat. REQUIRED when `background.featOpen` is true (an open slot — the build rejects the draft without it); optional on a fixed-feat background, where supplying it swaps the authored default. Must be an Origin-category feat (from `kind: 'feat'`)."New value: +"The background's feat, from the `originFeatCategory` feats. REQUIRED when `background.featOpen` is true (an open slot — the build rejects the draft without it); optional on a fixed-feat background, where supplying it swaps the authored default. Must be a feat in the `originFeatCategory` (from `kind: 'feat'`)."
      • changedInput schema / properties / castingAbilityPicks / description
        Previous value: -"Spellcasting-ability picks for `spellChoices` blocks that carry `castingAbilityOptions` (the lineage \"Intelligence, Wisdom, or Charisma is your spellcasting ability\" wording). Key is `\"<ruleId>:<blockIndex>\"` (same keying as `spellChoicePicks`); value is ONE lowercase ability name from that block's `castingAbilityOptions`. The projection surfaces `castingAbilityOptions` only when a pick is genuinely required (a fixed ability or a single option self-resolves server-side) — so whenever you see the array, supply a pick or the build rejects the draft. The resolved ability is stamped on each granted spell (`spells[].castingAbility`). A `repeatable` background feat prefixes the key `bg:<featId>:<blockIndex>` (same keying as spellChoicePicks)."New value: +"Spellcasting-ability picks for `spellChoices` blocks that carry `castingAbilityOptions` (a grant that lets the player choose the casting ability). Key is `\"<ruleId>:<blockIndex>\"` (same keying as `spellChoicePicks`); value is ONE lowercase ability name from that block's `castingAbilityOptions`. The projection surfaces `castingAbilityOptions` only when a pick is genuinely required (a fixed ability or a single option self-resolves server-side) — so whenever you see the array, supply a pick or the build rejects the draft. The resolved ability is stamped on each granted spell (`spells[].castingAbility`). A `repeatable` background feat prefixes the key `bg:<featId>:<blockIndex>` (same keying as spellChoicePicks)."
      • changedInput schema / properties / languages / description
        Previous value: -"The character's OWN chosen language names (e.g. ['Elvish','Draconic']). 'Common' is added server-side. `constants.languages.options` + `pickCount` are the conventional pool and count, but vault stores whatever is passed here — free-form names are allowed and the count is not enforced. (Languages a background/species GRANTS go in `languageChoicePicks`, not here.)"New value: +"The character's OWN chosen language names. The build adds any language the ruleset gives every character. `constants.languages.options` + `pickCount` are the conventional pool and count, but vault stores whatever is passed here — free-form names are allowed and the count is not enforced. (Languages a background/species GRANTS go in `languageChoicePicks`, not here.)"
      • changedInput schema / properties / preparedSpellPicks / description
        Previous value: -"Which leveled spells the player keeps prepared, for rules carrying a `preparedSpells` count. Key is the granting rule `_id`; value is spell `_id`s drawn from the character's granted leveled spells — `spellChoices` picks, whole-pool fixed grants, and `spellListChoices` picks alike — EXCLUDING spells that are already prepared: cantrips, and any spell granted by a block whose `prepared` flag is true (an always-prepared grant; the options projection ships `prepared` on each block so you can tell). The required count is the grant's count CLAMPED to that pool's size — send exactly min(count, preparable leveled spells). A `repeatable` feat filling the background slot keys `bg:<featId>` instead of `<featId>`."New value: +"Which spells the player keeps prepared, for rules carrying a `preparedSpells` count. Key is the granting rule `_id`; value is spell `_id`s drawn from the character's preparable granted spells — `spellChoices` picks, whole-pool fixed grants, and `spellListChoices` picks alike — EXCLUDING any granted by a block whose `prepared` flag is true (an always-prepared grant; the options projection ships `prepared` on each block so you can tell) and any the count does not cover (the rule authoring guide's preparedSpells section says which). The rule authoring guide.s preparedSpells section gives the required count; vault rejects picks that do not fit. A `repeatable` feat filling the background slot keys `bg:<featId>` instead of `<featId>`."
      • changedInput schema / properties / proficiencyChoicePicks / description
        Previous value: -"Picks for proficiencyChoices grants across ALL applied rules (class/species/feat/abilities). Key is `\"<ruleId>:<grantIndex>\"` (the Rule `_id` and the 0-based index into that rule's `proficiencyChoices`); value is the chosen names (skills/tools/saves/weapons/armor/languages). Only supply for grants where `count` < the option-pool size — fixed grants (count >= pool) are auto-applied and need no pick. A grant with `level: \"expertise\"` draws from the character's PROFICIENT skills (proficiency from every source applies first, then expertise), granting the expertise state rather than proficiency. A `repeatable` feat filling the background slot prefixes its keys `bg:<featId>:<grantIndex>` (not `<featId>:<grantIndex>`)."New value: +"Picks for proficiencyChoices grants across ALL applied rules (class/species/feat/abilities). Key is `\"<ruleId>:<grantIndex>\"` (the Rule `_id` and the 0-based index into that rule's `proficiencyChoices`); value is the chosen names (skills/tools/saves/weapons/armor/languages). Only supply for grants where `count` < the option-pool size — fixed grants (count >= pool) are auto-applied and need no pick. A grant with `level: \"expertise\"` grants the expertise state rather than proficiency, from the pool the rule authoring guide describes (proficiencyChoices). A `repeatable` feat filling the background slot prefixes its keys `bg:<featId>:<grantIndex>` (not `<featId>:<grantIndex>`)."
      • removedInput schema / properties / ruleset / default
        Removed value: -"5e24"
      • changedInput schema / properties / ruleset / description
        Previous value: -"Ruleset. Only '5e24' supports guided creation today."New value: +"A ruleset with guided character creation: the one the options were read for with `vault_get_pc_creation_options`."
      • changedInput schema / properties / speciesAbilityChoices / description
        Previous value: -"Same as `abilityChoices`, for a species ability's `choice` (e.g. a Human's 'Versatile' → an Origin feat). A picked option's own sub-choices (any type — Ability or Feat) go in the proficiency/spell pick maps keyed by that option's `_id`."New value: +"Same as `abilityChoices`, for a species ability's `choice`. A picked option's own sub-choices (any type — Ability or Feat) go in the proficiency/spell pick maps keyed by that option's `_id`."
      • changedInput schema / properties / speciesRuleId / description
        Previous value: -"`_id` of a Species/Race rule (from `kind: 'species'`)."New value: +"`_id` of the heritage rule (from `kind: 'species'`)."
      • changedInput schema / properties / spellChoicePicks / description
        Previous value: -"Picks for `spellChoices` blocks across ALL applied rules (class/species/feat/abilities). Key is `\"<ruleId>:<blockIndex>\"` (the Rule `_id` and the 0-based index into that rule's `spellChoices` AS PROJECTED — the array may contain null entries holding the position of blocks that grant nothing at level 1; count them when indexing, never compact the array). Value is the chosen spell `_id`s. Only supply where a block's `count` < its option-pool size — a whole-pool block is granted automatically. Each block's options come from `vault_get_pc_creation_options` (an applied ability/feat's `spellChoices[].options`). A `repeatable` feat filling the background slot prefixes its keys `bg:<featId>:<blockIndex>`."New value: +"Picks for `spellChoices` blocks across ALL applied rules (class/species/feat/abilities). Key is `\"<ruleId>:<blockIndex>\"` (the Rule `_id` and the 0-based index into that rule's `spellChoices` AS PROJECTED — the array may contain null entries holding the position of blocks that grant nothing at the starting level; count them when indexing, never compact the array). Value is the chosen spell `_id`s. Only supply where a block's `count` < its option-pool size — a whole-pool block is granted automatically. Each block's options come from `vault_get_pc_creation_options` (an applied ability/feat's `spellChoices[].options`). A `repeatable` feat filling the background slot prefixes its keys `bg:<featId>:<blockIndex>`."
      • changedInput schema / properties / spellListChoicePicks / description
        Previous value: -"Picks for `spellListChoices` blocks (the Magic Initiate shape: choose ONE class list, then spells from that one list). Key is `\"<ruleId>:<blockIndex>\"` (the projected array may contain null entries holding the position of blocks the build skips — count them when indexing, never compact); value is `{ category, picks }` where `category` is one of the block's `categories` and `picks` is `{ \"<pickIndex>\": [spellId, …] }` — the chosen spells for each pick, drawn from that pick's `optionsByCategory[category]`. When the block carries `castingAbilityOptions`, also set `castingAbility` (one lowercase ability name from those options) — the build rejects the draft without it. A `repeatable` feat filling the background slot prefixes its keys `bg:<featId>:<blockIndex>`."New value: +"Picks for `spellListChoices` blocks (choose ONE of the block's lists, then spells from that one list). Key is `\"<ruleId>:<blockIndex>\"` (the projected array may contain null entries holding the position of blocks the build skips — count them when indexing, never compact); value is `{ category, picks }` where `category` is one of the block's `categories` and `picks` is `{ \"<pickIndex>\": [spellId, …] }` — the chosen spells for each pick, drawn from that pick's `optionsByCategory[category]`. When the block carries `castingAbilityOptions`, also set `castingAbility` (one lowercase ability name from those options) — the build rejects the draft without it. A `repeatable` feat filling the background slot prefixes its keys `bg:<featId>:<blockIndex>`."
      • changedInput schema / properties / weaponAbilityChoices / description
        Previous value: -"For finesse weapons in the chosen bundle: key is the item `_id`, value is the attack ability ('strength' or 'dexterity')."New value: +"For a weapon in the chosen bundle whose attack ability is a player pick: key is the item `_id`, value is the attack ability (one of the schema's enum)."
      • changedInput schema / required
        Previous value: -[
        -  "name",
        -  "classRuleId",
        -  "abilityScoreMethod",
        -  "abilityScoreAssignments",
        -  "skillProficiencies",
        -  "toolProficiencies",
        -  "startingEquipmentLabel"
        -]New value: +[
        +  "ruleset",
        +  "name",
        +  "classRuleId",
        +  "abilityScoreMethod",
        +  "abilityScoreAssignments",
        +  "skillProficiencies",
        +  "toolProficiencies",
        +  "startingEquipmentLabel"
        +]
    • Changedvault_create_character46 fields changed
      • changedInput schema / properties / actions / items / properties / actions / description
        Previous value: -"PF Playtest action-economy marker (F/1/2/3/R)."New value: +"Action-cost marker, for rulesets whose actions carry one; the value is the source text."
      • changedInput schema / properties / actions / items / properties / attack / properties / attribute / description
        Previous value: -"Ability driving the to-hit roll (e.g. 'strength', 'charisma' for spell attacks)."New value: +"Ability driving the to-hit roll."
      • changedInput schema / properties / actions / items / properties / rof / description
        Previous value: -"Savage Worlds Rate of Fire."New value: +"Rate of fire, for rulesets whose actions carry one."
      • changedInput schema / properties / actions / items / properties / type / description
        Previous value: -"Action type. 5e24 uses 'Melee' / 'Range' / 'Special' / 'Reaction' / 'Legendary' / 'Bonus'."New value: +"Action type, as the ruleset's sheet names it."
      • changedInput schema / properties / aspects / items / properties / kind / description
        Previous value: -"One of 'high concept', 'trouble', 'character', 'consequence'."New value: +"The aspect's kind. The values are the ones the ruleset's sheet template uses; read a character of that ruleset (vault_get_character) to see them."
      • changedInput schema / properties / aspects / items / properties / shifts / description
        Previous value: -"Consequence/condition slots only: harm absorbed. Fate: 2 Mild, 4 Moderate, 6 Severe, 8 Extreme (Fate Accelerated omits Extreme). Demon Hunters conditions: 5 Mild, 10 Moderate, 15 Severe."New value: +"Consequence/condition slots only: the harm the slot absorbs, as the ruleset's sheet template sets it per slot."
      • changedInput schema / properties / attributes / items / properties / misc / description
        Previous value: -"Misc bonus on the save (5e/5e24). Used for high-PB monster compensation."New value: +"Misc bonus on the save. The monster authoring guide covers when a monster uses it."
      • changedInput schema / properties / attributes / items / properties / name / description
        Previous value: -"Ability name: strength / dexterity / constitution / intelligence / wisdom / charisma. Lowercase."New value: +"Ability id, lowercase (a value from the abilities list the typed tools' schemas carry)."
      • changedInput schema / properties / attributes / items / properties / proficient / description
        Previous value: -"Save proficiency flag (5e/5e24). When true, PB is added to the save."New value: +"Save proficiency flag. The sheet applies it to the save total."
      • changedInput schema / properties / attributes / items / properties / score / description
        Previous value: -"Raw ability score (e.g. 17). Modifier is derived by the sheet."New value: +"Raw ability score. Modifier is derived by the sheet."
      • changedInput schema / properties / core / properties / race / description
        Previous value: -"Creature type for monsters (e.g. 'Elemental', 'Humanoid', 'Dragon (Chromatic)'); race for PCs."New value: +"Creature type for monsters (source text); race for PCs."
      • changedInput schema / properties / core / properties / refresh / description
        Previous value: -"Session-start resource: fate points (Fate — Refresh) or faith dice (Demon Hunters — Devotion). The total the character resets to at the start of a session."New value: +"Session-start resource: the total the character resets to at the start of a session. The sheet template of the character's ruleset labels it."
      • changedInput schema / properties / core / properties / size / description
        Previous value: -"Creature size. Exact source text including 'or' for variable sizes ('Medium or Small')."New value: +"Creature size. Exact source text including 'or' for variable sizes ('X or Y')."
      • changedInput schema / properties / defense / properties / armorClass / description
        Previous value: -"Layered AC rows the sheet sums. IMPORTANT (5e24): when the character's `settings.autoPassiveBonuses` is true — the default for new 5e24 characters — the `armor` and `shield` rows are DERIVED from equipped items and recomputed on every sheet load, so writing them here gets overwritten. Change AC by setting `equipped: true/false` on the character's armor/shield items instead. When the toggle is false (and on all other rulesets), these rows are manually authored and writing them here is correct. `magic` and `misc` are manual in both modes. Check the toggle with vault_get_character before writing."New value: +"Layered AC rows the sheet sums. IMPORTANT: when the character's `settings.autoPassiveBonuses` is true — the default for new characters in rulesets with sheet automation — the `armor` and `shield` rows are DERIVED from equipped items and recomputed on every sheet load, so writing them here gets overwritten. Change AC by setting `equipped: true/false` on the character's armor/shield items instead. When the toggle is false (and on rulesets without sheet automation), these rows are manually authored and writing them here is correct. `magic` and `misc` are manual in both modes. Check the toggle with vault_get_character before writing."
      • changedInput schema / properties / defense / properties / armorClass / properties / armor / properties / bonus / description
        Previous value: -"Base AC value the sheet adds DEX to. See the 5e24 monster guide Rule 1 for the math."New value: +"Base AC value the sheet builds the total from. The monster authoring guide's Rule 1 gives the math."
      • changedInput schema / properties / defense / properties / armorClass / properties / armor / properties / description / description
        Previous value: -"Armor name ('Natural Armor', 'Chain Shirt') or null when AC derives from DEX only."New value: +"Armor name, source text, or null when no armor applies."
      • changedInput schema / properties / defense / properties / armorClass / properties / armor / properties / heavy / description
        Previous value: -"True suppresses DEX contribution entirely (heavy armor)."New value: +"True for heavy armor; the engine applies that armor weight's rule to the total."
      • changedInput schema / properties / defense / properties / armorClass / properties / armor / properties / medium / description
        Previous value: -"True caps DEX contribution to +2 (medium armor)."New value: +"True for medium armor; the engine applies that armor weight's rule to the total."
      • changedInput schema / properties / defense / properties / exhaustion / description
        Previous value: -"5e24 Exhaustion level (0-6). Absent = 0 (not exhausted). Each level is -2 to d20 Tests and -5 ft Speed; level 6 = death. A Long Rest via the vault rest control reduces it by 1."New value: +"Exhaustion level, within the schema's range. Absent = not exhausted. The engine applies its effects and reduces it on a rest taken through the vault rest control."
      • changedInput schema / properties / defense / properties / hitDice / properties / current / description
        Previous value: -"Unspent hit dice count. When `pools` is present (5e24 class characters), this is the derived sum of pool currents — keep it consistent with pools on write."New value: +"Unspent hit dice count. When `pools` is present, this is the derived sum of pool currents — keep it consistent with pools on write."
      • changedInput schema / properties / defense / properties / hitDice / properties / dice / description
        Previous value: -"Without `pools` (monsters, non-5e24): per-die expression, NOT the multiplied total — size-mapped Tiny d4 / Small d6 / Medium d8 / Large d10 / Huge d12 / Gargantuan d20, see monster guide Rule 20. When `pools` is present (5e24 class characters): the derived compound string ('5d10 + 5d6') — keep it consistent with pools on write."New value: +"Without `pools` (monsters, and sheets without pools): one die expression ('1dX'), NOT the multiplied total; the monster guide's Rule 20 gives a monster's die. When `pools` is present: the derived compound string, one 'NdX' term per pool joined by ' + ' — keep it consistent with pools on write."
      • changedInput schema / properties / defense / properties / hitDice / properties / pools / description
        Previous value: -"5e24 per-die-size Hit Dice pools — the AUTHORITATIVE representation (one entry per die size a multiclass character has). Maintained by creation, level-up, and a one-shot backfill; player edits win. The server does NOT re-derive the legacy fields on write, so when writing hit dice for a character with pools, write pools AND the legacy current/dice consistently (current = sum of pool currents; dice = compound string)."New value: +"Per-die-size Hit Dice pools, present on class characters the creation and level-up tools maintain — the AUTHORITATIVE representation (one entry per die size a multiclass character has). Maintained by creation, level-up, and a one-shot backfill; player edits win. The server does NOT re-derive the legacy fields on write, so when writing hit dice for a character with pools, write pools AND the legacy current/dice consistently (current = sum of pool currents; dice = compound string)."
      • changedInput schema / properties / defense / properties / hitDice / properties / pools / items / properties / dice / description
        Previous value: -"Die size of this pool, e.g. 'd10'."New value: +"Die size of this pool."
      • changedInput schema / properties / items / items / properties / sourceSpell / description
        Previous value: -"Auto-managed. Link to the spell that manufactured this companion armor item (e.g. Mage Armor, which the vault sheet offers as an equippable Light armor). The sheet sets and maintains it; if it's present on an item you're editing, preserve it verbatim, and never set, change, or invent it. Dropping it on a round-trip de-links the companion and leaves a duplicate item on the sheet."New value: +"Auto-managed. Link to the spell that manufactured this companion armor item (a spell the vault sheet offers as equippable armor). The sheet sets and maintains it; if it's present on an item you're editing, preserve it verbatim, and never set, change, or invent it. Dropping it on a round-trip de-links the companion and leaves a duplicate item on the sheet."
      • changedInput schema / properties / offense / properties / initiative / properties / attribute / description
        Previous value: -"Ability whose modifier drives initiative. Typically 'dexterity'."New value: +"Ability whose modifier drives initiative, lowercase."
      • changedInput schema / properties / rules / items / properties / statBonuses / items / properties / durationCount / description
        Previous value: -"Numeric count paired with durationUnit (e.g. count: 3, unit: 'round')."New value: +"Numeric count paired with durationUnit."
      • changedInput schema / properties / rules / items / properties / statBonuses / items / properties / range / description
        Previous value: -"Aura radius in feet for ally/any-audience bonuses (Aura of Protection's 10 ft.). Absent = no range filter."New value: +"Aura radius in feet for ally/any-audience bonuses. Absent = no range filter."
      • changedInput schema / properties / rules / items / properties / statBonuses / items / properties / requires / items / properties / armorCategories / description
        Previous value: -"For 'equipped' + slot:armor: armor category list (Light / Medium / Heavy). OR semantics — match any."New value: +"Armor categories to match, as the items' `armorCategory` values name them. OR semantics — match any."
      • changedInput schema / properties / rules / items / properties / statBonuses / items / properties / requires / items / properties / condition / description
        Previous value: -"For 'condition' predicates: the character-state condition to gate on (5e24 named conditions and ongoing-action states)."New value: +"For 'condition' predicates: the character-state condition to gate on (named conditions and ongoing-action states)."
      • changedInput schema / properties / rules / items / properties / statBonuses / items / properties / requires / items / properties / condition / enum
        Previous value: -[
        -  "blinded",
        -  "charmed",
        -  "dazed",
        -  "deafened",
        -  "exhaustion",
        -  "frightened",
        -  "grappled",
        -  "incapacitated",
        -  "invisible",
        -  "paralyzed",
        -  "petrified",
        -  "poisoned",
        -  "prone",
        -  "restrained",
        -  "stunned",
        -  "unconscious",
        -  "concentrating",
        -  "grappling",
        -  "dodging",
        -  "hiding",
        -  "raging"
        -]New value: +[
        +  "blinded",
        +  "charmed",
        +  "concentration",
        +  "deafened",
        +  "exhaustion",
        +  "frightened",
        +  "grappled",
        +  "incapacitated",
        +  "invisible",
        +  "paralyzed",
        +  "petrified",
        +  "poisoned",
        +  "prone",
        +  "restrained",
        +  "stunned",
        +  "unconscious",
        +  "dazed",
        +  "grappling",
        +  "dodging",
        +  "hiding",
        +  "raging"
        +]
      • changedInput schema / properties / rules / items / properties / statBonuses / items / properties / requires / items / properties / equipSlot / description
        Previous value: -"Body slot the matched weapon must occupy. mainHand / offHand. Resolved via getRequiredSlots so two-handed grips occupy both."New value: +"Body slot the matched weapon must occupy (one of the schema's enum)."
      • changedInput schema / properties / rules / items / properties / statBonuses / items / properties / requires / items / properties / slot / description
        Previous value: -"For 'equipped' predicates: the body category to match (armor / shield / weapon)."New value: +"The equipped body category to match (one of the schema's enum)."
      • changedInput schema / properties / rules / items / properties / statBonuses / items / properties / requires / items / properties / type / description
        Previous value: -"Predicate type. 'equipped' = character-scoped (gates on what's equipped). 'attackingWeapon' = attack-scoped (gates on the current action's source weapon). 'condition' = gates on a character-state condition."New value: +"Predicate type (one of the schema's enum): what the predicate gates on."
      • changedInput schema / properties / rules / items / properties / statBonuses / items / properties / requires / items / properties / weaponProperties / description
        Previous value: -"For 'equipped' + slot:weapon OR 'attackingWeapon': weapon-property list. AND semantics — match all."New value: +"Weapon properties to match. AND semantics — match all."
      • changedInput schema / properties / rules / items / properties / statBonuses / items / properties / target / description
        Previous value: -"Stat the bonus contributes to (e.g. 'skills.Acrobatics.misc', 'attributes.strength.misc')."New value: +"Stat the bonus contributes to (e.g. 'skills.<skill>.misc', 'attributes.<ability>.misc')."
      • changedInput schema / properties / rules / items / properties / statBonuses / items / properties / trigger / description
        Previous value: -"Action-economy / cost shape of the bonus. passive / toggled / reaction / perRoll / resource / targetBound."New value: +"Action-economy / cost shape of the bonus."
      • changedInput schema / properties / rules / items / properties / statBonuses / items / properties / triggerEvent / description
        Previous value: -"Game-time event that fires the bonus (onHit / onDamage / startOfYourTurn / etc.). Absent = not event-driven (passive walker contributes whenever `requires` holds)."New value: +"Game-time event that fires the bonus (one of the schema's trigger events). Absent = not event-driven (passive walker contributes whenever `requires` holds)."
      • changedInput schema / properties / rules / items / properties / statBonuses / items / properties / valueType / enum
        Previous value: -[
        -  "fixed",
        -  "attribute",
        -  "proficiency",
        -  "level",
        -  "halfLevel",
        -  "dice",
        -  "byLevel",
        -  "attackAttribute"
        -]New value: +[
        +  "fixed",
        +  "attribute",
        +  "attackAttribute",
        +  "proficiency",
        +  "level",
        +  "halfLevel",
        +  "dice",
        +  "byLevel"
        +]
      • changedInput schema / properties / rules / items / properties / type / description
        Previous value: -"Rule type (Ability / Feat / Class / Background / etc.). Vault validates against its rulestype enum on save."New value: +"Rule type. Vault validates it on save."
      • changedInput schema / properties / ruleset / description
        Previous value: -"Ruleset code (e.g. '5th Edition', '5e24', 'PFRPG', 'Savage Worlds'). Required. Restricted rulesets require an entitlement grant on the account — vault answers 403 for ungranted or unknown codes. Check list_rulesets for the codes this account can use."New value: +"Ruleset code, from list_rulesets (the codes this account can use). Required. Restricted rulesets require an entitlement grant on the account — vault answers 403 for ungranted or unknown codes."
      • changedInput schema / properties / settings / properties / autoPassiveBonuses / description
        Previous value: -"When true, the per-character rules engine layer contributes statBonuses from rules / items / feats. On 5e24 it ALSO derives the armor/shield rows of defense.armorClass from equipped items, recomputed on every sheet load — manual writes to those rows do not stick while this is true. Monsters should set this to false."New value: +"When true, the per-character rules engine layer contributes statBonuses from rules / items / feats. On rulesets with sheet automation it ALSO derives the armor/shield rows of defense.armorClass from equipped items, recomputed on every sheet load — manual writes to those rows do not stick while this is true. Monsters should set this to false."
      • changedInput schema / properties / settings / properties / hiddenSections / description
        Previous value: -"Sheet-section keys the player chose to hide while the section is empty ('spells', 'abilities', 'feats', 'origin', 'actionCards', 'hindrances', 'edges', 'stunts', 'extras'). A section with content always renders regardless of this list — the preference means 'hide when empty', never 'hide my data'."New value: +"Keys of the character sheet's sections the player chose to hide while the section is empty. A section with content always renders regardless of this list — the preference means 'hide when empty', never 'hide my data'."
      • changedInput schema / properties / skills / items / properties / rating / description
        Previous value: -"Fate: ladder position, -2 (Terrible) to +8 (Legendary); also an FAE approach's rating. Demon Hunters: the trait's die size (4, 6, 8, 10, or 12), or 0 for an unrated Fringe discipline."New value: +"The rating, on the ruleset's own scale. The ruleset's sheet template sets it; read a character of that ruleset (vault_get_character) to see the values."
      • changedInput schema / properties / spells / items / properties / recovery / description
        Previous value: -"Per-rest recovery rows for a finite free-cast counter, stamped from the granting rule's freeCast.recovery whenever the counter is created or grown (creation build and level-up). The vault rest control refills the counter from these when the player declares a Short/Long rest. Absent = the counter doesn't refresh on rest."New value: +"Per-rest recovery rows for a finite free-cast counter, stamped from the granting rule's freeCast.recovery whenever the counter is created or grown (creation build and level-up). The vault rest control refills the counter from these when the player declares the rest a row's `on` field names. Absent = the counter doesn't refresh on rest."
      • changedInput schema / properties / stress / items / properties / name / description
        Previous value: -"Track name — 'Physical Stress' / 'Mental Stress' in Fate Core, 'Stress' in Fate Accelerated."New value: +"Track name, as the ruleset's sheet template names its tracks."
      • changedInput schema / properties / trackables / items / properties / slotLevel / description
        Previous value: -"Spell-slot level of this pool (Pact Magic: one pool whose level rises with character level), stamped at build from the granting rule's uses[].slotLevel. The sheet shows it on the trackable row ('Level N'). Absent = an ordinary counter."New value: +"Spell-slot level of this pool, stamped at build from the granting rule's uses[].slotLevel. The sheet shows it on the trackable row ('Level N'). Absent = an ordinary counter."
    • Changedvault_create_item73 fields changed
      • changedInput schema / properties / abilityScoreBump / properties / options / items / properties / lines / items / properties / eligible / description
        Previous value: -"Pool to choose from. Empty / absent = any of the six."New value: +"Pool to choose from. Empty / absent = any ability in the schema's abilities list."
      • changedInput schema / properties / abilityScoreBump / properties / options / items / properties / lines / items / properties / max / description
        Previous value: -"Ceiling no chosen score may exceed after the bump (ASI = 20)."New value: +"Ceiling no chosen score may exceed after the bump. The rule authoring guide's abilityScoreBump section shows the values."
      • changedInput schema / properties / abilityScoreBump / properties / options / items / properties / lines / items / properties / max / maximum
        Previous value: -9007199254740991New value: +30
      • changedInput schema / properties / abilityScoreSet / items / properties / value / maximum
        Previous value: -9007199254740991New value: +30
      • changedInput schema / properties / armorCategory / description
        Previous value: -"Armor category ('Light', 'Medium', 'Heavy', 'Shield')."New value: +"Armor category, as the ruleset's catalog names it (vault_search_items shows them)."
      • changedInput schema / properties / damageReduction / items / properties / requires / items / properties / armorCategories / description
        Previous value: -"For 'equipped' + slot:armor: armor category list (Light / Medium / Heavy). OR semantics — match any."New value: +"Armor categories to match, as the items' `armorCategory` values name them. OR semantics — match any."
      • changedInput schema / properties / damageReduction / items / properties / requires / items / properties / condition / description
        Previous value: -"For 'condition' predicates: the character-state condition to gate on (5e24 named conditions and ongoing-action states)."New value: +"For 'condition' predicates: the character-state condition to gate on (named conditions and ongoing-action states)."
      • changedInput schema / properties / damageReduction / items / properties / requires / items / properties / condition / enum
        Previous value: -[
        -  "blinded",
        -  "charmed",
        -  "dazed",
        -  "deafened",
        -  "exhaustion",
        -  "frightened",
        -  "grappled",
        -  "incapacitated",
        -  "invisible",
        -  "paralyzed",
        -  "petrified",
        -  "poisoned",
        -  "prone",
        -  "restrained",
        -  "stunned",
        -  "unconscious",
        -  "concentrating",
        -  "grappling",
        -  "dodging",
        -  "hiding",
        -  "raging"
        -]New value: +[
        +  "blinded",
        +  "charmed",
        +  "concentration",
        +  "deafened",
        +  "exhaustion",
        +  "frightened",
        +  "grappled",
        +  "incapacitated",
        +  "invisible",
        +  "paralyzed",
        +  "petrified",
        +  "poisoned",
        +  "prone",
        +  "restrained",
        +  "stunned",
        +  "unconscious",
        +  "dazed",
        +  "grappling",
        +  "dodging",
        +  "hiding",
        +  "raging"
        +]
      • changedInput schema / properties / damageReduction / items / properties / requires / items / properties / equipSlot / description
        Previous value: -"Body slot the matched weapon must occupy. mainHand / offHand. Resolved via getRequiredSlots so two-handed grips occupy both."New value: +"Body slot the matched weapon must occupy (one of the schema's enum)."
      • changedInput schema / properties / damageReduction / items / properties / requires / items / properties / slot / description
        Previous value: -"For 'equipped' predicates: the body category to match (armor / shield / weapon)."New value: +"The equipped body category to match (one of the schema's enum)."
      • changedInput schema / properties / damageReduction / items / properties / requires / items / properties / type / description
        Previous value: -"Predicate type. 'equipped' = character-scoped (gates on what's equipped). 'attackingWeapon' = attack-scoped (gates on the current action's source weapon). 'condition' = gates on a character-state condition."New value: +"Predicate type (one of the schema's enum): what the predicate gates on."
      • changedInput schema / properties / damageReduction / items / properties / requires / items / properties / weaponProperties / description
        Previous value: -"For 'equipped' + slot:weapon OR 'attackingWeapon': weapon-property list. AND semantics — match all."New value: +"Weapon properties to match. AND semantics — match all."
      • changedInput schema / properties / diceFloors / items / properties / requires / items / properties / armorCategories / description
        Previous value: -"For 'equipped' + slot:armor: armor category list (Light / Medium / Heavy). OR semantics — match any."New value: +"Armor categories to match, as the items' `armorCategory` values name them. OR semantics — match any."
      • changedInput schema / properties / diceFloors / items / properties / requires / items / properties / condition / description
        Previous value: -"For 'condition' predicates: the character-state condition to gate on (5e24 named conditions and ongoing-action states)."New value: +"For 'condition' predicates: the character-state condition to gate on (named conditions and ongoing-action states)."
      • changedInput schema / properties / diceFloors / items / properties / requires / items / properties / condition / enum
        Previous value: -[
        -  "blinded",
        -  "charmed",
        -  "dazed",
        -  "deafened",
        -  "exhaustion",
        -  "frightened",
        -  "grappled",
        -  "incapacitated",
        -  "invisible",
        -  "paralyzed",
        -  "petrified",
        -  "poisoned",
        -  "prone",
        -  "restrained",
        -  "stunned",
        -  "unconscious",
        -  "concentrating",
        -  "grappling",
        -  "dodging",
        -  "hiding",
        -  "raging"
        -]New value: +[
        +  "blinded",
        +  "charmed",
        +  "concentration",
        +  "deafened",
        +  "exhaustion",
        +  "frightened",
        +  "grappled",
        +  "incapacitated",
        +  "invisible",
        +  "paralyzed",
        +  "petrified",
        +  "poisoned",
        +  "prone",
        +  "restrained",
        +  "stunned",
        +  "unconscious",
        +  "dazed",
        +  "grappling",
        +  "dodging",
        +  "hiding",
        +  "raging"
        +]
      • changedInput schema / properties / diceFloors / items / properties / requires / items / properties / equipSlot / description
        Previous value: -"Body slot the matched weapon must occupy. mainHand / offHand. Resolved via getRequiredSlots so two-handed grips occupy both."New value: +"Body slot the matched weapon must occupy (one of the schema's enum)."
      • changedInput schema / properties / diceFloors / items / properties / requires / items / properties / slot / description
        Previous value: -"For 'equipped' predicates: the body category to match (armor / shield / weapon)."New value: +"The equipped body category to match (one of the schema's enum)."
      • changedInput schema / properties / diceFloors / items / properties / requires / items / properties / type / description
        Previous value: -"Predicate type. 'equipped' = character-scoped (gates on what's equipped). 'attackingWeapon' = attack-scoped (gates on the current action's source weapon). 'condition' = gates on a character-state condition."New value: +"Predicate type (one of the schema's enum): what the predicate gates on."
      • changedInput schema / properties / diceFloors / items / properties / requires / items / properties / weaponProperties / description
        Previous value: -"For 'equipped' + slot:weapon OR 'attackingWeapon': weapon-property list. AND semantics — match all."New value: +"Weapon properties to match. AND semantics — match all."
      • changedInput schema / properties / diceReplacements / items / properties / requires / items / properties / armorCategories / description
        Previous value: -"For 'equipped' + slot:armor: armor category list (Light / Medium / Heavy). OR semantics — match any."New value: +"Armor categories to match, as the items' `armorCategory` values name them. OR semantics — match any."
      • changedInput schema / properties / diceReplacements / items / properties / requires / items / properties / condition / description
        Previous value: -"For 'condition' predicates: the character-state condition to gate on (5e24 named conditions and ongoing-action states)."New value: +"For 'condition' predicates: the character-state condition to gate on (named conditions and ongoing-action states)."
      • changedInput schema / properties / diceReplacements / items / properties / requires / items / properties / condition / enum
        Previous value: -[
        -  "blinded",
        -  "charmed",
        -  "dazed",
        -  "deafened",
        -  "exhaustion",
        -  "frightened",
        -  "grappled",
        -  "incapacitated",
        -  "invisible",
        -  "paralyzed",
        -  "petrified",
        -  "poisoned",
        -  "prone",
        -  "restrained",
        -  "stunned",
        -  "unconscious",
        -  "concentrating",
        -  "grappling",
        -  "dodging",
        -  "hiding",
        -  "raging"
        -]New value: +[
        +  "blinded",
        +  "charmed",
        +  "concentration",
        +  "deafened",
        +  "exhaustion",
        +  "frightened",
        +  "grappled",
        +  "incapacitated",
        +  "invisible",
        +  "paralyzed",
        +  "petrified",
        +  "poisoned",
        +  "prone",
        +  "restrained",
        +  "stunned",
        +  "unconscious",
        +  "dazed",
        +  "grappling",
        +  "dodging",
        +  "hiding",
        +  "raging"
        +]
      • changedInput schema / properties / diceReplacements / items / properties / requires / items / properties / equipSlot / description
        Previous value: -"Body slot the matched weapon must occupy. mainHand / offHand. Resolved via getRequiredSlots so two-handed grips occupy both."New value: +"Body slot the matched weapon must occupy (one of the schema's enum)."
      • changedInput schema / properties / diceReplacements / items / properties / requires / items / properties / slot / description
        Previous value: -"For 'equipped' predicates: the body category to match (armor / shield / weapon)."New value: +"The equipped body category to match (one of the schema's enum)."
      • changedInput schema / properties / diceReplacements / items / properties / requires / items / properties / type / description
        Previous value: -"Predicate type. 'equipped' = character-scoped (gates on what's equipped). 'attackingWeapon' = attack-scoped (gates on the current action's source weapon). 'condition' = gates on a character-state condition."New value: +"Predicate type (one of the schema's enum): what the predicate gates on."
      • changedInput schema / properties / diceReplacements / items / properties / requires / items / properties / weaponProperties / description
        Previous value: -"For 'equipped' + slot:weapon OR 'attackingWeapon': weapon-property list. AND semantics — match all."New value: +"Weapon properties to match. AND semantics — match all."
      • changedInput schema / properties / equipSlots / description
        Previous value: -"Allowed equip slot ids (e.g. 'mainHand', 'offHand', 'body'). Vocabulary is ruleset-specific."New value: +"Allowed equip slot ids, from the ruleset's own slots (an existing item's equipSlots, via vault_get_item, shows them)."
      • changedInput schema / properties / forcedMovement / items / properties / requires / items / properties / armorCategories / description
        Previous value: -"For 'equipped' + slot:armor: armor category list (Light / Medium / Heavy). OR semantics — match any."New value: +"Armor categories to match, as the items' `armorCategory` values name them. OR semantics — match any."
      • changedInput schema / properties / forcedMovement / items / properties / requires / items / properties / condition / description
        Previous value: -"For 'condition' predicates: the character-state condition to gate on (5e24 named conditions and ongoing-action states)."New value: +"For 'condition' predicates: the character-state condition to gate on (named conditions and ongoing-action states)."
      • changedInput schema / properties / forcedMovement / items / properties / requires / items / properties / condition / enum
        Previous value: -[
        -  "blinded",
        -  "charmed",
        -  "dazed",
        -  "deafened",
        -  "exhaustion",
        -  "frightened",
        -  "grappled",
        -  "incapacitated",
        -  "invisible",
        -  "paralyzed",
        -  "petrified",
        -  "poisoned",
        -  "prone",
        -  "restrained",
        -  "stunned",
        -  "unconscious",
        -  "concentrating",
        -  "grappling",
        -  "dodging",
        -  "hiding",
        -  "raging"
        -]New value: +[
        +  "blinded",
        +  "charmed",
        +  "concentration",
        +  "deafened",
        +  "exhaustion",
        +  "frightened",
        +  "grappled",
        +  "incapacitated",
        +  "invisible",
        +  "paralyzed",
        +  "petrified",
        +  "poisoned",
        +  "prone",
        +  "restrained",
        +  "stunned",
        +  "unconscious",
        +  "dazed",
        +  "grappling",
        +  "dodging",
        +  "hiding",
        +  "raging"
        +]
      • changedInput schema / properties / forcedMovement / items / properties / requires / items / properties / equipSlot / description
        Previous value: -"Body slot the matched weapon must occupy. mainHand / offHand. Resolved via getRequiredSlots so two-handed grips occupy both."New value: +"Body slot the matched weapon must occupy (one of the schema's enum)."
      • changedInput schema / properties / forcedMovement / items / properties / requires / items / properties / slot / description
        Previous value: -"For 'equipped' predicates: the body category to match (armor / shield / weapon)."New value: +"The equipped body category to match (one of the schema's enum)."
      • changedInput schema / properties / forcedMovement / items / properties / requires / items / properties / type / description
        Previous value: -"Predicate type. 'equipped' = character-scoped (gates on what's equipped). 'attackingWeapon' = attack-scoped (gates on the current action's source weapon). 'condition' = gates on a character-state condition."New value: +"Predicate type (one of the schema's enum): what the predicate gates on."
      • changedInput schema / properties / forcedMovement / items / properties / requires / items / properties / weaponProperties / description
        Previous value: -"For 'equipped' + slot:weapon OR 'attackingWeapon': weapon-property list. AND semantics — match all."New value: +"Weapon properties to match. AND semantics — match all."
      • changedInput schema / properties / mastery / description
        Previous value: -"5e24 weapon mastery name (e.g. 'Topple', 'Vex', 'Slow')."New value: +"Weapon mastery name, for rulesets whose weapons carry one, as the ruleset's catalog names it."
      • changedInput schema / properties / maxDexModifier / description
        Previous value: -"Cap on DEX bonus from this armor (medium = 2; heavy = 0 typically)."New value: +"Cap on the DEX bonus this armor allows, from the item's source text."
      • changedInput schema / properties / prerequisites / items / properties / abilities / description
        Previous value: -"For abilityScore: ANY listed ability meeting `min` satisfies ('Str or Dex 13+')."New value: +"For abilityScore: ANY listed ability meeting `min` satisfies."
      • changedInput schema / properties / prerequisites / items / properties / proficiency / description
        Previous value: -"For proficiency: the proficiency name (e.g. 'Martial', 'Stealth')."New value: +"For proficiency: the proficiency name, as the ruleset names it."
      • changedInput schema / properties / prerequisites / items / properties / proficiencyType / enum
        Previous value: -[
        -  "skill",
        -  "tool",
        -  "weapon",
        -  "armor",
        -  "save",
        -  "language"
        -]New value: +[
        +  "skill",
        +  "tool",
        +  "save",
        +  "weapon",
        +  "armor",
        +  "language"
        +]
      • changedInput schema / properties / prerequisites / items / properties / type / description
        Previous value: -"Predicate kind: level / abilityScore / rule / spell / proficiency / spellcasting. (A class is required via a `rule` predicate pointing at the class rule.)"New value: +"Predicate kind. (A class is required via a `rule` predicate pointing at the class rule.)"
      • changedInput schema / properties / properties / items / properties / ammoType / description
        Previous value: -"Ammunition type for the Ammunition property (e.g. 'Arrow', 'Bolt')."New value: +"Ammunition type, for a property that uses ammunition."
      • changedInput schema / properties / properties / items / properties / damage / description
        Previous value: -"Per-property damage dice override (e.g. Versatile's two-hand dice)."New value: +"Per-property damage dice override, for a property that changes the weapon's damage."
      • changedInput schema / properties / properties / items / properties / name / description
        Previous value: -"Property identifier (e.g. 'Finesse', 'Versatile', 'Ammunition')."New value: +"Property identifier, as the ruleset's catalog names it (vault_search_items shows them)."
      • changedInput schema / properties / recurringDamage / items / properties / requires / items / properties / armorCategories / description
        Previous value: -"For 'equipped' + slot:armor: armor category list (Light / Medium / Heavy). OR semantics — match any."New value: +"Armor categories to match, as the items' `armorCategory` values name them. OR semantics — match any."
      • changedInput schema / properties / recurringDamage / items / properties / requires / items / properties / condition / description
        Previous value: -"For 'condition' predicates: the character-state condition to gate on (5e24 named conditions and ongoing-action states)."New value: +"For 'condition' predicates: the character-state condition to gate on (named conditions and ongoing-action states)."
      • changedInput schema / properties / recurringDamage / items / properties / requires / items / properties / condition / enum
        Previous value: -[
        -  "blinded",
        -  "charmed",
        -  "dazed",
        -  "deafened",
        -  "exhaustion",
        -  "frightened",
        -  "grappled",
        -  "incapacitated",
        -  "invisible",
        -  "paralyzed",
        -  "petrified",
        -  "poisoned",
        -  "prone",
        -  "restrained",
        -  "stunned",
        -  "unconscious",
        -  "concentrating",
        -  "grappling",
        -  "dodging",
        -  "hiding",
        -  "raging"
        -]New value: +[
        +  "blinded",
        +  "charmed",
        +  "concentration",
        +  "deafened",
        +  "exhaustion",
        +  "frightened",
        +  "grappled",
        +  "incapacitated",
        +  "invisible",
        +  "paralyzed",
        +  "petrified",
        +  "poisoned",
        +  "prone",
        +  "restrained",
        +  "stunned",
        +  "unconscious",
        +  "dazed",
        +  "grappling",
        +  "dodging",
        +  "hiding",
        +  "raging"
        +]
      • changedInput schema / properties / recurringDamage / items / properties / requires / items / properties / equipSlot / description
        Previous value: -"Body slot the matched weapon must occupy. mainHand / offHand. Resolved via getRequiredSlots so two-handed grips occupy both."New value: +"Body slot the matched weapon must occupy (one of the schema's enum)."
      • changedInput schema / properties / recurringDamage / items / properties / requires / items / properties / slot / description
        Previous value: -"For 'equipped' predicates: the body category to match (armor / shield / weapon)."New value: +"The equipped body category to match (one of the schema's enum)."
      • changedInput schema / properties / recurringDamage / items / properties / requires / items / properties / type / description
        Previous value: -"Predicate type. 'equipped' = character-scoped (gates on what's equipped). 'attackingWeapon' = attack-scoped (gates on the current action's source weapon). 'condition' = gates on a character-state condition."New value: +"Predicate type (one of the schema's enum): what the predicate gates on."
      • changedInput schema / properties / recurringDamage / items / properties / requires / items / properties / weaponProperties / description
        Previous value: -"For 'equipped' + slot:weapon OR 'attackingWeapon': weapon-property list. AND semantics — match all."New value: +"Weapon properties to match. AND semantics — match all."
      • changedInput schema / properties / resistances / items / properties / range / description
        Previous value: -"Aura radius in feet for ally/any-targeted resistances (Warding Aura's 10 ft.). Absent = self-only."New value: +"Aura radius in feet for ally/any-targeted resistances. Absent = self-only."
      • changedInput schema / properties / rollMods / items / properties / requires / items / properties / armorCategories / description
        Previous value: -"For 'equipped' + slot:armor: armor category list (Light / Medium / Heavy). OR semantics — match any."New value: +"Armor categories to match, as the items' `armorCategory` values name them. OR semantics — match any."
      • changedInput schema / properties / rollMods / items / properties / requires / items / properties / condition / description
        Previous value: -"For 'condition' predicates: the character-state condition to gate on (5e24 named conditions and ongoing-action states)."New value: +"For 'condition' predicates: the character-state condition to gate on (named conditions and ongoing-action states)."
      • changedInput schema / properties / rollMods / items / properties / requires / items / properties / condition / enum
        Previous value: -[
        -  "blinded",
        -  "charmed",
        -  "dazed",
        -  "deafened",
        -  "exhaustion",
        -  "frightened",
        -  "grappled",
        -  "incapacitated",
        -  "invisible",
        -  "paralyzed",
        -  "petrified",
        -  "poisoned",
        -  "prone",
        -  "restrained",
        -  "stunned",
        -  "unconscious",
        -  "concentrating",
        -  "grappling",
        -  "dodging",
        -  "hiding",
        -  "raging"
        -]New value: +[
        +  "blinded",
        +  "charmed",
        +  "concentration",
        +  "deafened",
        +  "exhaustion",
        +  "frightened",
        +  "grappled",
        +  "incapacitated",
        +  "invisible",
        +  "paralyzed",
        +  "petrified",
        +  "poisoned",
        +  "prone",
        +  "restrained",
        +  "stunned",
        +  "unconscious",
        +  "dazed",
        +  "grappling",
        +  "dodging",
        +  "hiding",
        +  "raging"
        +]
      • changedInput schema / properties / rollMods / items / properties / requires / items / properties / equipSlot / description
        Previous value: -"Body slot the matched weapon must occupy. mainHand / offHand. Resolved via getRequiredSlots so two-handed grips occupy both."New value: +"Body slot the matched weapon must occupy (one of the schema's enum)."
      • changedInput schema / properties / rollMods / items / properties / requires / items / properties / slot / description
        Previous value: -"For 'equipped' predicates: the body category to match (armor / shield / weapon)."New value: +"The equipped body category to match (one of the schema's enum)."
      • changedInput schema / properties / rollMods / items / properties / requires / items / properties / type / description
        Previous value: -"Predicate type. 'equipped' = character-scoped (gates on what's equipped). 'attackingWeapon' = attack-scoped (gates on the current action's source weapon). 'condition' = gates on a character-state condition."New value: +"Predicate type (one of the schema's enum): what the predicate gates on."
      • changedInput schema / properties / rollMods / items / properties / requires / items / properties / weaponProperties / description
        Previous value: -"For 'equipped' + slot:weapon OR 'attackingWeapon': weapon-property list. AND semantics — match all."New value: +"Weapon properties to match. AND semantics — match all."
      • changedInput schema / properties / ruleset / description
        Previous value: -"Ruleset code (e.g. '5th Edition', '5e24', 'PFRPG', 'Savage Worlds')."New value: +"Ruleset code, from list_rulesets."
      • changedInput schema / properties / statBonuses / items / properties / durationCount / description
        Previous value: -"Numeric count paired with durationUnit (e.g. count: 3, unit: 'round')."New value: +"Numeric count paired with durationUnit."
      • changedInput schema / properties / statBonuses / items / properties / range / description
        Previous value: -"Aura radius in feet for ally/any-audience bonuses (Aura of Protection's 10 ft.). Absent = no range filter."New value: +"Aura radius in feet for ally/any-audience bonuses. Absent = no range filter."
      • changedInput schema / properties / statBonuses / items / properties / requires / items / properties / armorCategories / description
        Previous value: -"For 'equipped' + slot:armor: armor category list (Light / Medium / Heavy). OR semantics — match any."New value: +"Armor categories to match, as the items' `armorCategory` values name them. OR semantics — match any."
      • changedInput schema / properties / statBonuses / items / properties / requires / items / properties / condition / description
        Previous value: -"For 'condition' predicates: the character-state condition to gate on (5e24 named conditions and ongoing-action states)."New value: +"For 'condition' predicates: the character-state condition to gate on (named conditions and ongoing-action states)."
      • changedInput schema / properties / statBonuses / items / properties / requires / items / properties / condition / enum
        Previous value: -[
        -  "blinded",
        -  "charmed",
        -  "dazed",
        -  "deafened",
        -  "exhaustion",
        -  "frightened",
        -  "grappled",
        -  "incapacitated",
        -  "invisible",
        -  "paralyzed",
        -  "petrified",
        -  "poisoned",
        -  "prone",
        -  "restrained",
        -  "stunned",
        -  "unconscious",
        -  "concentrating",
        -  "grappling",
        -  "dodging",
        -  "hiding",
        -  "raging"
        -]New value: +[
        +  "blinded",
        +  "charmed",
        +  "concentration",
        +  "deafened",
        +  "exhaustion",
        +  "frightened",
        +  "grappled",
        +  "incapacitated",
        +  "invisible",
        +  "paralyzed",
        +  "petrified",
        +  "poisoned",
        +  "prone",
        +  "restrained",
        +  "stunned",
        +  "unconscious",
        +  "dazed",
        +  "grappling",
        +  "dodging",
        +  "hiding",
        +  "raging"
        +]
      • changedInput schema / properties / statBonuses / items / properties / requires / items / properties / equipSlot / description
        Previous value: -"Body slot the matched weapon must occupy. mainHand / offHand. Resolved via getRequiredSlots so two-handed grips occupy both."New value: +"Body slot the matched weapon must occupy (one of the schema's enum)."
      • changedInput schema / properties / statBonuses / items / properties / requires / items / properties / slot / description
        Previous value: -"For 'equipped' predicates: the body category to match (armor / shield / weapon)."New value: +"The equipped body category to match (one of the schema's enum)."
      • changedInput schema / properties / statBonuses / items / properties / requires / items / properties / type / description
        Previous value: -"Predicate type. 'equipped' = character-scoped (gates on what's equipped). 'attackingWeapon' = attack-scoped (gates on the current action's source weapon). 'condition' = gates on a character-state condition."New value: +"Predicate type (one of the schema's enum): what the predicate gates on."
      • changedInput schema / properties / statBonuses / items / properties / requires / items / properties / weaponProperties / description
        Previous value: -"For 'equipped' + slot:weapon OR 'attackingWeapon': weapon-property list. AND semantics — match all."New value: +"Weapon properties to match. AND semantics — match all."
      • changedInput schema / properties / statBonuses / items / properties / target / description
        Previous value: -"Stat the bonus contributes to (e.g. 'skills.Acrobatics.misc', 'attributes.strength.misc')."New value: +"Stat the bonus contributes to (e.g. 'skills.<skill>.misc', 'attributes.<ability>.misc')."
      • changedInput schema / properties / statBonuses / items / properties / trigger / description
        Previous value: -"Action-economy / cost shape of the bonus. passive / toggled / reaction / perRoll / resource / targetBound."New value: +"Action-economy / cost shape of the bonus."
      • changedInput schema / properties / statBonuses / items / properties / triggerEvent / description
        Previous value: -"Game-time event that fires the bonus (onHit / onDamage / startOfYourTurn / etc.). Absent = not event-driven (passive walker contributes whenever `requires` holds)."New value: +"Game-time event that fires the bonus (one of the schema's trigger events). Absent = not event-driven (passive walker contributes whenever `requires` holds)."
      • changedInput schema / properties / statBonuses / items / properties / valueType / enum
        Previous value: -[
        -  "fixed",
        -  "attribute",
        -  "proficiency",
        -  "level",
        -  "halfLevel",
        -  "dice",
        -  "byLevel",
        -  "attackAttribute"
        -]New value: +[
        +  "fixed",
        +  "attribute",
        +  "attackAttribute",
        +  "proficiency",
        +  "level",
        +  "halfLevel",
        +  "dice",
        +  "byLevel"
        +]
      • changedInput schema / properties / weaponType / description
        Previous value: -"Weapon category ('Simple Melee', 'Martial Ranged', etc.)."New value: +"Weapon category, as the ruleset's catalog names it (vault_search_items shows them)."
    • Changedvault_create_rule73 fields changed
      • changedInput schema / properties / abilityScoreBump / properties / options / items / properties / lines / items / properties / eligible / description
        Previous value: -"Pool to choose from. Empty / absent = any of the six."New value: +"Pool to choose from. Empty / absent = any ability in the schema's abilities list."
      • changedInput schema / properties / abilityScoreBump / properties / options / items / properties / lines / items / properties / max / description
        Previous value: -"Ceiling no chosen score may exceed after the bump (ASI = 20)."New value: +"Ceiling no chosen score may exceed after the bump. The rule authoring guide's abilityScoreBump section shows the values."
      • changedInput schema / properties / abilityScoreBump / properties / options / items / properties / lines / items / properties / max / maximum
        Previous value: -9007199254740991New value: +30
      • changedInput schema / properties / abilityScoreSet / items / properties / value / maximum
        Previous value: -9007199254740991New value: +30
      • changedInput schema / properties / actionEconomy / description
        Previous value: -"What invoking the ability costs on a turn: 'Action', 'Bonus Action', or 'Reaction'. Distinct from the mechanics actionType (a kind-of-action label). Absent = the ability takes the action."New value: +"What invoking the ability costs on a turn. The rule authoring guide (vault_get_authoring_guide, entityType 'rule') gives the absent default. Distinct from the mechanics actionType (a kind-of-action label)."
      • addedInput schema / properties / actionEconomy / enum
        Added value: +[
        +  "Action",
        +  "Bonus Action",
        +  "Reaction"
        +]
      • changedInput schema / properties / actions / description
        Previous value: -"PF Playtest action-economy marker (F/1/2/3/R)."New value: +"Action-cost marker, for rulesets whose rules carry one; the value is the source text."
      • changedInput schema / properties / casterProgression / description
        Previous value: -"How this class contributes to the combined multiclass spell-slot pool: full casters count every level, half/third round up, 'pact' (Pact Magic) keeps its own pool and never joins. Authorable on a base class or a subclass (a third-caster subclass carries it). Absent = non-caster."New value: +"How this class contributes to the combined multiclass spell-slot pool; the engine applies each progression's rule. Authorable on a base class or a subclass (a subclass that grants the casting carries it). Absent = non-caster."
      • changedInput schema / properties / castingAbility / description
        Previous value: -"The ability this rule's spellcasting keys off ('Intelligence is your spellcasting ability for your Wizard spells'). Author it on a class's Spellcasting ability rule; vault's creation and level-up wizards write it to the character-wide Spellcasting Ability (first-wins, never overwriting), and a multiclass whose ability differs stamps its granted spells per-entry. Distinct from a spell block's castingAbility, which overrides per grant. Absent = the rule says nothing about the character's casting ability."New value: +"The ability this rule's spellcasting keys off. Author it on a class's Spellcasting ability rule; vault's creation and level-up wizards write it to the character-wide Spellcasting Ability (first-wins, never overwriting), and a multiclass whose ability differs stamps its granted spells per-entry. Distinct from a spell block's castingAbility, which overrides per grant. Absent = the rule says nothing about the character's casting ability."
      • changedInput schema / properties / damageReduction / items / properties / requires / items / properties / armorCategories / description
        Previous value: -"For 'equipped' + slot:armor: armor category list (Light / Medium / Heavy). OR semantics — match any."New value: +"Armor categories to match, as the items' `armorCategory` values name them. OR semantics — match any."
      • changedInput schema / properties / damageReduction / items / properties / requires / items / properties / condition / description
        Previous value: -"For 'condition' predicates: the character-state condition to gate on (5e24 named conditions and ongoing-action states)."New value: +"For 'condition' predicates: the character-state condition to gate on (named conditions and ongoing-action states)."
      • changedInput schema / properties / damageReduction / items / properties / requires / items / properties / condition / enum
        Previous value: -[
        -  "blinded",
        -  "charmed",
        -  "dazed",
        -  "deafened",
        -  "exhaustion",
        -  "frightened",
        -  "grappled",
        -  "incapacitated",
        -  "invisible",
        -  "paralyzed",
        -  "petrified",
        -  "poisoned",
        -  "prone",
        -  "restrained",
        -  "stunned",
        -  "unconscious",
        -  "concentrating",
        -  "grappling",
        -  "dodging",
        -  "hiding",
        -  "raging"
        -]New value: +[
        +  "blinded",
        +  "charmed",
        +  "concentration",
        +  "deafened",
        +  "exhaustion",
        +  "frightened",
        +  "grappled",
        +  "incapacitated",
        +  "invisible",
        +  "paralyzed",
        +  "petrified",
        +  "poisoned",
        +  "prone",
        +  "restrained",
        +  "stunned",
        +  "unconscious",
        +  "dazed",
        +  "grappling",
        +  "dodging",
        +  "hiding",
        +  "raging"
        +]
      • changedInput schema / properties / damageReduction / items / properties / requires / items / properties / equipSlot / description
        Previous value: -"Body slot the matched weapon must occupy. mainHand / offHand. Resolved via getRequiredSlots so two-handed grips occupy both."New value: +"Body slot the matched weapon must occupy (one of the schema's enum)."
      • changedInput schema / properties / damageReduction / items / properties / requires / items / properties / slot / description
        Previous value: -"For 'equipped' predicates: the body category to match (armor / shield / weapon)."New value: +"The equipped body category to match (one of the schema's enum)."
      • changedInput schema / properties / damageReduction / items / properties / requires / items / properties / type / description
        Previous value: -"Predicate type. 'equipped' = character-scoped (gates on what's equipped). 'attackingWeapon' = attack-scoped (gates on the current action's source weapon). 'condition' = gates on a character-state condition."New value: +"Predicate type (one of the schema's enum): what the predicate gates on."
      • changedInput schema / properties / damageReduction / items / properties / requires / items / properties / weaponProperties / description
        Previous value: -"For 'equipped' + slot:weapon OR 'attackingWeapon': weapon-property list. AND semantics — match all."New value: +"Weapon properties to match. AND semantics — match all."
      • changedInput schema / properties / diceFloors / items / properties / requires / items / properties / armorCategories / description
        Previous value: -"For 'equipped' + slot:armor: armor category list (Light / Medium / Heavy). OR semantics — match any."New value: +"Armor categories to match, as the items' `armorCategory` values name them. OR semantics — match any."
      • changedInput schema / properties / diceFloors / items / properties / requires / items / properties / condition / description
        Previous value: -"For 'condition' predicates: the character-state condition to gate on (5e24 named conditions and ongoing-action states)."New value: +"For 'condition' predicates: the character-state condition to gate on (named conditions and ongoing-action states)."
      • changedInput schema / properties / diceFloors / items / properties / requires / items / properties / condition / enum
        Previous value: -[
        -  "blinded",
        -  "charmed",
        -  "dazed",
        -  "deafened",
        -  "exhaustion",
        -  "frightened",
        -  "grappled",
        -  "incapacitated",
        -  "invisible",
        -  "paralyzed",
        -  "petrified",
        -  "poisoned",
        -  "prone",
        -  "restrained",
        -  "stunned",
        -  "unconscious",
        -  "concentrating",
        -  "grappling",
        -  "dodging",
        -  "hiding",
        -  "raging"
        -]New value: +[
        +  "blinded",
        +  "charmed",
        +  "concentration",
        +  "deafened",
        +  "exhaustion",
        +  "frightened",
        +  "grappled",
        +  "incapacitated",
        +  "invisible",
        +  "paralyzed",
        +  "petrified",
        +  "poisoned",
        +  "prone",
        +  "restrained",
        +  "stunned",
        +  "unconscious",
        +  "dazed",
        +  "grappling",
        +  "dodging",
        +  "hiding",
        +  "raging"
        +]
      • changedInput schema / properties / diceFloors / items / properties / requires / items / properties / equipSlot / description
        Previous value: -"Body slot the matched weapon must occupy. mainHand / offHand. Resolved via getRequiredSlots so two-handed grips occupy both."New value: +"Body slot the matched weapon must occupy (one of the schema's enum)."
      • changedInput schema / properties / diceFloors / items / properties / requires / items / properties / slot / description
        Previous value: -"For 'equipped' predicates: the body category to match (armor / shield / weapon)."New value: +"The equipped body category to match (one of the schema's enum)."
      • changedInput schema / properties / diceFloors / items / properties / requires / items / properties / type / description
        Previous value: -"Predicate type. 'equipped' = character-scoped (gates on what's equipped). 'attackingWeapon' = attack-scoped (gates on the current action's source weapon). 'condition' = gates on a character-state condition."New value: +"Predicate type (one of the schema's enum): what the predicate gates on."
      • changedInput schema / properties / diceFloors / items / properties / requires / items / properties / weaponProperties / description
        Previous value: -"For 'equipped' + slot:weapon OR 'attackingWeapon': weapon-property list. AND semantics — match all."New value: +"Weapon properties to match. AND semantics — match all."
      • changedInput schema / properties / diceReplacements / items / properties / requires / items / properties / armorCategories / description
        Previous value: -"For 'equipped' + slot:armor: armor category list (Light / Medium / Heavy). OR semantics — match any."New value: +"Armor categories to match, as the items' `armorCategory` values name them. OR semantics — match any."
      • changedInput schema / properties / diceReplacements / items / properties / requires / items / properties / condition / description
        Previous value: -"For 'condition' predicates: the character-state condition to gate on (5e24 named conditions and ongoing-action states)."New value: +"For 'condition' predicates: the character-state condition to gate on (named conditions and ongoing-action states)."
      • changedInput schema / properties / diceReplacements / items / properties / requires / items / properties / condition / enum
        Previous value: -[
        -  "blinded",
        -  "charmed",
        -  "dazed",
        -  "deafened",
        -  "exhaustion",
        -  "frightened",
        -  "grappled",
        -  "incapacitated",
        -  "invisible",
        -  "paralyzed",
        -  "petrified",
        -  "poisoned",
        -  "prone",
        -  "restrained",
        -  "stunned",
        -  "unconscious",
        -  "concentrating",
        -  "grappling",
        -  "dodging",
        -  "hiding",
        -  "raging"
        -]New value: +[
        +  "blinded",
        +  "charmed",
        +  "concentration",
        +  "deafened",
        +  "exhaustion",
        +  "frightened",
        +  "grappled",
        +  "incapacitated",
        +  "invisible",
        +  "paralyzed",
        +  "petrified",
        +  "poisoned",
        +  "prone",
        +  "restrained",
        +  "stunned",
        +  "unconscious",
        +  "dazed",
        +  "grappling",
        +  "dodging",
        +  "hiding",
        +  "raging"
        +]
      • changedInput schema / properties / diceReplacements / items / properties / requires / items / properties / equipSlot / description
        Previous value: -"Body slot the matched weapon must occupy. mainHand / offHand. Resolved via getRequiredSlots so two-handed grips occupy both."New value: +"Body slot the matched weapon must occupy (one of the schema's enum)."
      • changedInput schema / properties / diceReplacements / items / properties / requires / items / properties / slot / description
        Previous value: -"For 'equipped' predicates: the body category to match (armor / shield / weapon)."New value: +"The equipped body category to match (one of the schema's enum)."
      • changedInput schema / properties / diceReplacements / items / properties / requires / items / properties / type / description
        Previous value: -"Predicate type. 'equipped' = character-scoped (gates on what's equipped). 'attackingWeapon' = attack-scoped (gates on the current action's source weapon). 'condition' = gates on a character-state condition."New value: +"Predicate type (one of the schema's enum): what the predicate gates on."
      • changedInput schema / properties / diceReplacements / items / properties / requires / items / properties / weaponProperties / description
        Previous value: -"For 'equipped' + slot:weapon OR 'attackingWeapon': weapon-property list. AND semantics — match all."New value: +"Weapon properties to match. AND semantics — match all."
      • changedInput schema / properties / forcedMovement / items / properties / requires / items / properties / armorCategories / description
        Previous value: -"For 'equipped' + slot:armor: armor category list (Light / Medium / Heavy). OR semantics — match any."New value: +"Armor categories to match, as the items' `armorCategory` values name them. OR semantics — match any."
      • changedInput schema / properties / forcedMovement / items / properties / requires / items / properties / condition / description
        Previous value: -"For 'condition' predicates: the character-state condition to gate on (5e24 named conditions and ongoing-action states)."New value: +"For 'condition' predicates: the character-state condition to gate on (named conditions and ongoing-action states)."
      • changedInput schema / properties / forcedMovement / items / properties / requires / items / properties / condition / enum
        Previous value: -[
        -  "blinded",
        -  "charmed",
        -  "dazed",
        -  "deafened",
        -  "exhaustion",
        -  "frightened",
        -  "grappled",
        -  "incapacitated",
        -  "invisible",
        -  "paralyzed",
        -  "petrified",
        -  "poisoned",
        -  "prone",
        -  "restrained",
        -  "stunned",
        -  "unconscious",
        -  "concentrating",
        -  "grappling",
        -  "dodging",
        -  "hiding",
        -  "raging"
        -]New value: +[
        +  "blinded",
        +  "charmed",
        +  "concentration",
        +  "deafened",
        +  "exhaustion",
        +  "frightened",
        +  "grappled",
        +  "incapacitated",
        +  "invisible",
        +  "paralyzed",
        +  "petrified",
        +  "poisoned",
        +  "prone",
        +  "restrained",
        +  "stunned",
        +  "unconscious",
        +  "dazed",
        +  "grappling",
        +  "dodging",
        +  "hiding",
        +  "raging"
        +]
      • changedInput schema / properties / forcedMovement / items / properties / requires / items / properties / equipSlot / description
        Previous value: -"Body slot the matched weapon must occupy. mainHand / offHand. Resolved via getRequiredSlots so two-handed grips occupy both."New value: +"Body slot the matched weapon must occupy (one of the schema's enum)."
      • changedInput schema / properties / forcedMovement / items / properties / requires / items / properties / slot / description
        Previous value: -"For 'equipped' predicates: the body category to match (armor / shield / weapon)."New value: +"The equipped body category to match (one of the schema's enum)."
      • changedInput schema / properties / forcedMovement / items / properties / requires / items / properties / type / description
        Previous value: -"Predicate type. 'equipped' = character-scoped (gates on what's equipped). 'attackingWeapon' = attack-scoped (gates on the current action's source weapon). 'condition' = gates on a character-state condition."New value: +"Predicate type (one of the schema's enum): what the predicate gates on."
      • changedInput schema / properties / forcedMovement / items / properties / requires / items / properties / weaponProperties / description
        Previous value: -"For 'equipped' + slot:weapon OR 'attackingWeapon': weapon-property list. AND semantics — match all."New value: +"Weapon properties to match. AND semantics — match all."
      • changedInput schema / properties / prerequisites / items / properties / abilities / description
        Previous value: -"For abilityScore: ANY listed ability meeting `min` satisfies ('Str or Dex 13+')."New value: +"For abilityScore: ANY listed ability meeting `min` satisfies."
      • changedInput schema / properties / prerequisites / items / properties / proficiency / description
        Previous value: -"For proficiency: the proficiency name (e.g. 'Martial', 'Stealth')."New value: +"For proficiency: the proficiency name, as the ruleset names it."
      • changedInput schema / properties / prerequisites / items / properties / proficiencyType / enum
        Previous value: -[
        -  "skill",
        -  "tool",
        -  "weapon",
        -  "armor",
        -  "save",
        -  "language"
        -]New value: +[
        +  "skill",
        +  "tool",
        +  "save",
        +  "weapon",
        +  "armor",
        +  "language"
        +]
      • changedInput schema / properties / prerequisites / items / properties / type / description
        Previous value: -"Predicate kind: level / abilityScore / rule / spell / proficiency / spellcasting. (A class is required via a `rule` predicate pointing at the class rule.)"New value: +"Predicate kind. (A class is required via a `rule` predicate pointing at the class rule.)"
      • changedInput schema / properties / range / description
        Previous value: -"How far the ability reaches when invoked — self, touch, or ranged with a distance ('feet' default, 'miles' for long reaches). Absent = runtime defaults (self-heals on the user, targeted abilities at touch)."New value: +"How far the ability reaches when invoked: `kind`, plus `distance` and its `unit` for a kind that takes a distance. Absent: the rule authoring guide (vault_get_authoring_guide, entityType 'rule') gives the default."
      • changedInput schema / properties / recurringDamage / items / properties / requires / items / properties / armorCategories / description
        Previous value: -"For 'equipped' + slot:armor: armor category list (Light / Medium / Heavy). OR semantics — match any."New value: +"Armor categories to match, as the items' `armorCategory` values name them. OR semantics — match any."
      • changedInput schema / properties / recurringDamage / items / properties / requires / items / properties / condition / description
        Previous value: -"For 'condition' predicates: the character-state condition to gate on (5e24 named conditions and ongoing-action states)."New value: +"For 'condition' predicates: the character-state condition to gate on (named conditions and ongoing-action states)."
      • changedInput schema / properties / recurringDamage / items / properties / requires / items / properties / condition / enum
        Previous value: -[
        -  "blinded",
        -  "charmed",
        -  "dazed",
        -  "deafened",
        -  "exhaustion",
        -  "frightened",
        -  "grappled",
        -  "incapacitated",
        -  "invisible",
        -  "paralyzed",
        -  "petrified",
        -  "poisoned",
        -  "prone",
        -  "restrained",
        -  "stunned",
        -  "unconscious",
        -  "concentrating",
        -  "grappling",
        -  "dodging",
        -  "hiding",
        -  "raging"
        -]New value: +[
        +  "blinded",
        +  "charmed",
        +  "concentration",
        +  "deafened",
        +  "exhaustion",
        +  "frightened",
        +  "grappled",
        +  "incapacitated",
        +  "invisible",
        +  "paralyzed",
        +  "petrified",
        +  "poisoned",
        +  "prone",
        +  "restrained",
        +  "stunned",
        +  "unconscious",
        +  "dazed",
        +  "grappling",
        +  "dodging",
        +  "hiding",
        +  "raging"
        +]
      • changedInput schema / properties / recurringDamage / items / properties / requires / items / properties / equipSlot / description
        Previous value: -"Body slot the matched weapon must occupy. mainHand / offHand. Resolved via getRequiredSlots so two-handed grips occupy both."New value: +"Body slot the matched weapon must occupy (one of the schema's enum)."
      • changedInput schema / properties / recurringDamage / items / properties / requires / items / properties / slot / description
        Previous value: -"For 'equipped' predicates: the body category to match (armor / shield / weapon)."New value: +"The equipped body category to match (one of the schema's enum)."
      • changedInput schema / properties / recurringDamage / items / properties / requires / items / properties / type / description
        Previous value: -"Predicate type. 'equipped' = character-scoped (gates on what's equipped). 'attackingWeapon' = attack-scoped (gates on the current action's source weapon). 'condition' = gates on a character-state condition."New value: +"Predicate type (one of the schema's enum): what the predicate gates on."
      • changedInput schema / properties / recurringDamage / items / properties / requires / items / properties / weaponProperties / description
        Previous value: -"For 'equipped' + slot:weapon OR 'attackingWeapon': weapon-property list. AND semantics — match all."New value: +"Weapon properties to match. AND semantics — match all."
      • changedInput schema / properties / repeatable / description
        Previous value: -"A rule that may be taken/granted more than once, each time as a distinct instance with its own sub-choices — a repeatable Feat (Skilled, Resilient), or a class's Ability Score Improvement ability, which its class grants at several levels."New value: +"A rule that may be taken/granted more than once, each time as a distinct instance with its own sub-choices — a repeatable feat, or a class ability its class grants at several levels."
      • changedInput schema / properties / resistances / items / properties / range / description
        Previous value: -"Aura radius in feet for ally/any-targeted resistances (Warding Aura's 10 ft.). Absent = self-only."New value: +"Aura radius in feet for ally/any-targeted resistances. Absent = self-only."
      • changedInput schema / properties / rollMods / items / properties / requires / items / properties / armorCategories / description
        Previous value: -"For 'equipped' + slot:armor: armor category list (Light / Medium / Heavy). OR semantics — match any."New value: +"Armor categories to match, as the items' `armorCategory` values name them. OR semantics — match any."
      • changedInput schema / properties / rollMods / items / properties / requires / items / properties / condition / description
        Previous value: -"For 'condition' predicates: the character-state condition to gate on (5e24 named conditions and ongoing-action states)."New value: +"For 'condition' predicates: the character-state condition to gate on (named conditions and ongoing-action states)."
      • changedInput schema / properties / rollMods / items / properties / requires / items / properties / condition / enum
        Previous value: -[
        -  "blinded",
        -  "charmed",
        -  "dazed",
        -  "deafened",
        -  "exhaustion",
        -  "frightened",
        -  "grappled",
        -  "incapacitated",
        -  "invisible",
        -  "paralyzed",
        -  "petrified",
        -  "poisoned",
        -  "prone",
        -  "restrained",
        -  "stunned",
        -  "unconscious",
        -  "concentrating",
        -  "grappling",
        -  "dodging",
        -  "hiding",
        -  "raging"
        -]New value: +[
        +  "blinded",
        +  "charmed",
        +  "concentration",
        +  "deafened",
        +  "exhaustion",
        +  "frightened",
        +  "grappled",
        +  "incapacitated",
        +  "invisible",
        +  "paralyzed",
        +  "petrified",
        +  "poisoned",
        +  "prone",
        +  "restrained",
        +  "stunned",
        +  "unconscious",
        +  "dazed",
        +  "grappling",
        +  "dodging",
        +  "hiding",
        +  "raging"
        +]
      • changedInput schema / properties / rollMods / items / properties / requires / items / properties / equipSlot / description
        Previous value: -"Body slot the matched weapon must occupy. mainHand / offHand. Resolved via getRequiredSlots so two-handed grips occupy both."New value: +"Body slot the matched weapon must occupy (one of the schema's enum)."
      • changedInput schema / properties / rollMods / items / properties / requires / items / properties / slot / description
        Previous value: -"For 'equipped' predicates: the body category to match (armor / shield / weapon)."New value: +"The equipped body category to match (one of the schema's enum)."
      • changedInput schema / properties / rollMods / items / properties / requires / items / properties / type / description
        Previous value: -"Predicate type. 'equipped' = character-scoped (gates on what's equipped). 'attackingWeapon' = attack-scoped (gates on the current action's source weapon). 'condition' = gates on a character-state condition."New value: +"Predicate type (one of the schema's enum): what the predicate gates on."
      • changedInput schema / properties / rollMods / items / properties / requires / items / properties / weaponProperties / description
        Previous value: -"For 'equipped' + slot:weapon OR 'attackingWeapon': weapon-property list. AND semantics — match all."New value: +"Weapon properties to match. AND semantics — match all."
      • changedInput schema / properties / ruleset / description
        Previous value: -"Ruleset code (e.g. '5th Edition', '5e24', 'PFRPG', 'Savage Worlds', 'Universal')."New value: +"Ruleset code, from list_rulesets."
      • changedInput schema / properties / statBonuses / items / properties / durationCount / description
        Previous value: -"Numeric count paired with durationUnit (e.g. count: 3, unit: 'round')."New value: +"Numeric count paired with durationUnit."
      • changedInput schema / properties / statBonuses / items / properties / range / description
        Previous value: -"Aura radius in feet for ally/any-audience bonuses (Aura of Protection's 10 ft.). Absent = no range filter."New value: +"Aura radius in feet for ally/any-audience bonuses. Absent = no range filter."
      • changedInput schema / properties / statBonuses / items / properties / requires / items / properties / armorCategories / description
        Previous value: -"For 'equipped' + slot:armor: armor category list (Light / Medium / Heavy). OR semantics — match any."New value: +"Armor categories to match, as the items' `armorCategory` values name them. OR semantics — match any."
      • changedInput schema / properties / statBonuses / items / properties / requires / items / properties / condition / description
        Previous value: -"For 'condition' predicates: the character-state condition to gate on (5e24 named conditions and ongoing-action states)."New value: +"For 'condition' predicates: the character-state condition to gate on (named conditions and ongoing-action states)."
      • changedInput schema / properties / statBonuses / items / properties / requires / items / properties / condition / enum
        Previous value: -[
        -  "blinded",
        -  "charmed",
        -  "dazed",
        -  "deafened",
        -  "exhaustion",
        -  "frightened",
        -  "grappled",
        -  "incapacitated",
        -  "invisible",
        -  "paralyzed",
        -  "petrified",
        -  "poisoned",
        -  "prone",
        -  "restrained",
        -  "stunned",
        -  "unconscious",
        -  "concentrating",
        -  "grappling",
        -  "dodging",
        -  "hiding",
        -  "raging"
        -]New value: +[
        +  "blinded",
        +  "charmed",
        +  "concentration",
        +  "deafened",
        +  "exhaustion",
        +  "frightened",
        +  "grappled",
        +  "incapacitated",
        +  "invisible",
        +  "paralyzed",
        +  "petrified",
        +  "poisoned",
        +  "prone",
        +  "restrained",
        +  "stunned",
        +  "unconscious",
        +  "dazed",
        +  "grappling",
        +  "dodging",
        +  "hiding",
        +  "raging"
        +]
      • changedInput schema / properties / statBonuses / items / properties / requires / items / properties / equipSlot / description
        Previous value: -"Body slot the matched weapon must occupy. mainHand / offHand. Resolved via getRequiredSlots so two-handed grips occupy both."New value: +"Body slot the matched weapon must occupy (one of the schema's enum)."
      • changedInput schema / properties / statBonuses / items / properties / requires / items / properties / slot / description
        Previous value: -"For 'equipped' predicates: the body category to match (armor / shield / weapon)."New value: +"The equipped body category to match (one of the schema's enum)."
      • changedInput schema / properties / statBonuses / items / properties / requires / items / properties / type / description
        Previous value: -"Predicate type. 'equipped' = character-scoped (gates on what's equipped). 'attackingWeapon' = attack-scoped (gates on the current action's source weapon). 'condition' = gates on a character-state condition."New value: +"Predicate type (one of the schema's enum): what the predicate gates on."
      • changedInput schema / properties / statBonuses / items / properties / requires / items / properties / weaponProperties / description
        Previous value: -"For 'equipped' + slot:weapon OR 'attackingWeapon': weapon-property list. AND semantics — match all."New value: +"Weapon properties to match. AND semantics — match all."
      • changedInput schema / properties / statBonuses / items / properties / target / description
        Previous value: -"Stat the bonus contributes to (e.g. 'skills.Acrobatics.misc', 'attributes.strength.misc')."New value: +"Stat the bonus contributes to (e.g. 'skills.<skill>.misc', 'attributes.<ability>.misc')."
      • changedInput schema / properties / statBonuses / items / properties / trigger / description
        Previous value: -"Action-economy / cost shape of the bonus. passive / toggled / reaction / perRoll / resource / targetBound."New value: +"Action-economy / cost shape of the bonus."
      • changedInput schema / properties / statBonuses / items / properties / triggerEvent / description
        Previous value: -"Game-time event that fires the bonus (onHit / onDamage / startOfYourTurn / etc.). Absent = not event-driven (passive walker contributes whenever `requires` holds)."New value: +"Game-time event that fires the bonus (one of the schema's trigger events). Absent = not event-driven (passive walker contributes whenever `requires` holds)."
      • changedInput schema / properties / statBonuses / items / properties / valueType / enum
        Previous value: -[
        -  "fixed",
        -  "attribute",
        -  "proficiency",
        -  "level",
        -  "halfLevel",
        -  "dice",
        -  "byLevel",
        -  "attackAttribute"
        -]New value: +[
        +  "fixed",
        +  "attribute",
        +  "attackAttribute",
        +  "proficiency",
        +  "level",
        +  "halfLevel",
        +  "dice",
        +  "byLevel"
        +]
      • changedInput schema / properties / type / enum
        Previous value: -[
        -  "Ability",
        -  "Feat",
        -  "Action Card",
        -  "Hindrance",
        -  "Edge",
        -  "Class",
        -  "Background",
        -  "Race",
        -  "Species",
        -  "Ancestry",
        -  "Glossary",
        -  "Stunt",
        -  "Extra"
        -]New value: +[
        +  "Ability",
        +  "Feat",
        +  "Glossary",
        +  "Action Card",
        +  "Hindrance",
        +  "Edge",
        +  "Class",
        +  "Background",
        +  "Race",
        +  "Species",
        +  "Ancestry",
        +  "Stunt",
        +  "Extra"
        +]
    • Changedvault_create_spell80 fields changed
      • changedInput schema / properties / abilityScoreBump / properties / options / items / properties / lines / items / properties / eligible / description
        Previous value: -"Pool to choose from. Empty / absent = any of the six."New value: +"Pool to choose from. Empty / absent = any ability in the schema's abilities list."
      • changedInput schema / properties / abilityScoreBump / properties / options / items / properties / lines / items / properties / max / description
        Previous value: -"Ceiling no chosen score may exceed after the bump (ASI = 20)."New value: +"Ceiling no chosen score may exceed after the bump. The rule authoring guide's abilityScoreBump section shows the values."
      • changedInput schema / properties / abilityScoreBump / properties / options / items / properties / lines / items / properties / max / maximum
        Previous value: -9007199254740991New value: +30
      • changedInput schema / properties / abilityScoreSet / items / properties / value / maximum
        Previous value: -9007199254740991New value: +30
      • changedInput schema / properties / actions / description
        Previous value: -"PF Playtest action-economy marker (F/1/2/3/R)."New value: +"Action-cost marker, for rulesets whose spells carry one; the value is the source text."
      • changedInput schema / properties / area / description
        Previous value: -"Area of effect. shape ∈ cone|cube|cylinder|emanation|line|sphere; size (ft); width for line."New value: +"Area of effect. `shape`; `size` (ft); `width` for a line."
      • changedInput schema / properties / castingTime / description
        Previous value: -"Casting time. unit ∈ action|bonusAction|reaction|minute|hour; count for minute/hour."New value: +"Casting time. `unit`, plus `count` for a timed unit."
      • changedInput schema / properties / classes / description
        Previous value: -"Class-membership list for non-5.5e rulesets (e.g. PFRPG); 5.5e spells use `categories` instead. Free-form per ruleset."New value: +"Class-membership list for rulesets whose spells do not use `categories` (the spell authoring guide covers `categories`). Free-form per ruleset."
      • changedInput schema / properties / damageReduction / items / properties / requires / items / properties / armorCategories / description
        Previous value: -"For 'equipped' + slot:armor: armor category list (Light / Medium / Heavy). OR semantics — match any."New value: +"Armor categories to match, as the items' `armorCategory` values name them. OR semantics — match any."
      • changedInput schema / properties / damageReduction / items / properties / requires / items / properties / condition / description
        Previous value: -"For 'condition' predicates: the character-state condition to gate on (5e24 named conditions and ongoing-action states)."New value: +"For 'condition' predicates: the character-state condition to gate on (named conditions and ongoing-action states)."
      • changedInput schema / properties / damageReduction / items / properties / requires / items / properties / condition / enum
        Previous value: -[
        -  "blinded",
        -  "charmed",
        -  "dazed",
        -  "deafened",
        -  "exhaustion",
        -  "frightened",
        -  "grappled",
        -  "incapacitated",
        -  "invisible",
        -  "paralyzed",
        -  "petrified",
        -  "poisoned",
        -  "prone",
        -  "restrained",
        -  "stunned",
        -  "unconscious",
        -  "concentrating",
        -  "grappling",
        -  "dodging",
        -  "hiding",
        -  "raging"
        -]New value: +[
        +  "blinded",
        +  "charmed",
        +  "concentration",
        +  "deafened",
        +  "exhaustion",
        +  "frightened",
        +  "grappled",
        +  "incapacitated",
        +  "invisible",
        +  "paralyzed",
        +  "petrified",
        +  "poisoned",
        +  "prone",
        +  "restrained",
        +  "stunned",
        +  "unconscious",
        +  "dazed",
        +  "grappling",
        +  "dodging",
        +  "hiding",
        +  "raging"
        +]
      • changedInput schema / properties / damageReduction / items / properties / requires / items / properties / equipSlot / description
        Previous value: -"Body slot the matched weapon must occupy. mainHand / offHand. Resolved via getRequiredSlots so two-handed grips occupy both."New value: +"Body slot the matched weapon must occupy (one of the schema's enum)."
      • changedInput schema / properties / damageReduction / items / properties / requires / items / properties / slot / description
        Previous value: -"For 'equipped' predicates: the body category to match (armor / shield / weapon)."New value: +"The equipped body category to match (one of the schema's enum)."
      • changedInput schema / properties / damageReduction / items / properties / requires / items / properties / type / description
        Previous value: -"Predicate type. 'equipped' = character-scoped (gates on what's equipped). 'attackingWeapon' = attack-scoped (gates on the current action's source weapon). 'condition' = gates on a character-state condition."New value: +"Predicate type (one of the schema's enum): what the predicate gates on."
      • changedInput schema / properties / damageReduction / items / properties / requires / items / properties / weaponProperties / description
        Previous value: -"For 'equipped' + slot:weapon OR 'attackingWeapon': weapon-property list. AND semantics — match all."New value: +"Weapon properties to match. AND semantics — match all."
      • changedInput schema / properties / diceFloors / items / properties / requires / items / properties / armorCategories / description
        Previous value: -"For 'equipped' + slot:armor: armor category list (Light / Medium / Heavy). OR semantics — match any."New value: +"Armor categories to match, as the items' `armorCategory` values name them. OR semantics — match any."
      • changedInput schema / properties / diceFloors / items / properties / requires / items / properties / condition / description
        Previous value: -"For 'condition' predicates: the character-state condition to gate on (5e24 named conditions and ongoing-action states)."New value: +"For 'condition' predicates: the character-state condition to gate on (named conditions and ongoing-action states)."
      • changedInput schema / properties / diceFloors / items / properties / requires / items / properties / condition / enum
        Previous value: -[
        -  "blinded",
        -  "charmed",
        -  "dazed",
        -  "deafened",
        -  "exhaustion",
        -  "frightened",
        -  "grappled",
        -  "incapacitated",
        -  "invisible",
        -  "paralyzed",
        -  "petrified",
        -  "poisoned",
        -  "prone",
        -  "restrained",
        -  "stunned",
        -  "unconscious",
        -  "concentrating",
        -  "grappling",
        -  "dodging",
        -  "hiding",
        -  "raging"
        -]New value: +[
        +  "blinded",
        +  "charmed",
        +  "concentration",
        +  "deafened",
        +  "exhaustion",
        +  "frightened",
        +  "grappled",
        +  "incapacitated",
        +  "invisible",
        +  "paralyzed",
        +  "petrified",
        +  "poisoned",
        +  "prone",
        +  "restrained",
        +  "stunned",
        +  "unconscious",
        +  "dazed",
        +  "grappling",
        +  "dodging",
        +  "hiding",
        +  "raging"
        +]
      • changedInput schema / properties / diceFloors / items / properties / requires / items / properties / equipSlot / description
        Previous value: -"Body slot the matched weapon must occupy. mainHand / offHand. Resolved via getRequiredSlots so two-handed grips occupy both."New value: +"Body slot the matched weapon must occupy (one of the schema's enum)."
      • changedInput schema / properties / diceFloors / items / properties / requires / items / properties / slot / description
        Previous value: -"For 'equipped' predicates: the body category to match (armor / shield / weapon)."New value: +"The equipped body category to match (one of the schema's enum)."
      • changedInput schema / properties / diceFloors / items / properties / requires / items / properties / type / description
        Previous value: -"Predicate type. 'equipped' = character-scoped (gates on what's equipped). 'attackingWeapon' = attack-scoped (gates on the current action's source weapon). 'condition' = gates on a character-state condition."New value: +"Predicate type (one of the schema's enum): what the predicate gates on."
      • changedInput schema / properties / diceFloors / items / properties / requires / items / properties / weaponProperties / description
        Previous value: -"For 'equipped' + slot:weapon OR 'attackingWeapon': weapon-property list. AND semantics — match all."New value: +"Weapon properties to match. AND semantics — match all."
      • changedInput schema / properties / diceReplacements / items / properties / requires / items / properties / armorCategories / description
        Previous value: -"For 'equipped' + slot:armor: armor category list (Light / Medium / Heavy). OR semantics — match any."New value: +"Armor categories to match, as the items' `armorCategory` values name them. OR semantics — match any."
      • changedInput schema / properties / diceReplacements / items / properties / requires / items / properties / condition / description
        Previous value: -"For 'condition' predicates: the character-state condition to gate on (5e24 named conditions and ongoing-action states)."New value: +"For 'condition' predicates: the character-state condition to gate on (named conditions and ongoing-action states)."
      • changedInput schema / properties / diceReplacements / items / properties / requires / items / properties / condition / enum
        Previous value: -[
        -  "blinded",
        -  "charmed",
        -  "dazed",
        -  "deafened",
        -  "exhaustion",
        -  "frightened",
        -  "grappled",
        -  "incapacitated",
        -  "invisible",
        -  "paralyzed",
        -  "petrified",
        -  "poisoned",
        -  "prone",
        -  "restrained",
        -  "stunned",
        -  "unconscious",
        -  "concentrating",
        -  "grappling",
        -  "dodging",
        -  "hiding",
        -  "raging"
        -]New value: +[
        +  "blinded",
        +  "charmed",
        +  "concentration",
        +  "deafened",
        +  "exhaustion",
        +  "frightened",
        +  "grappled",
        +  "incapacitated",
        +  "invisible",
        +  "paralyzed",
        +  "petrified",
        +  "poisoned",
        +  "prone",
        +  "restrained",
        +  "stunned",
        +  "unconscious",
        +  "dazed",
        +  "grappling",
        +  "dodging",
        +  "hiding",
        +  "raging"
        +]
      • changedInput schema / properties / diceReplacements / items / properties / requires / items / properties / equipSlot / description
        Previous value: -"Body slot the matched weapon must occupy. mainHand / offHand. Resolved via getRequiredSlots so two-handed grips occupy both."New value: +"Body slot the matched weapon must occupy (one of the schema's enum)."
      • changedInput schema / properties / diceReplacements / items / properties / requires / items / properties / slot / description
        Previous value: -"For 'equipped' predicates: the body category to match (armor / shield / weapon)."New value: +"The equipped body category to match (one of the schema's enum)."
      • changedInput schema / properties / diceReplacements / items / properties / requires / items / properties / type / description
        Previous value: -"Predicate type. 'equipped' = character-scoped (gates on what's equipped). 'attackingWeapon' = attack-scoped (gates on the current action's source weapon). 'condition' = gates on a character-state condition."New value: +"Predicate type (one of the schema's enum): what the predicate gates on."
      • changedInput schema / properties / diceReplacements / items / properties / requires / items / properties / weaponProperties / description
        Previous value: -"For 'equipped' + slot:weapon OR 'attackingWeapon': weapon-property list. AND semantics — match all."New value: +"Weapon properties to match. AND semantics — match all."
      • changedInput schema / properties / duration / description
        Previous value: -"Spell duration. unit ∈ instantaneous | round | minute | hour | day | untilDispelled | untilDispelledOrTriggered | special; count for timed units; concentration flag; upTo flag for a non-concentration capped duration (\"Up to 1 minute\")."New value: +"Spell duration. `unit`; `count` for a timed unit; concentration flag; upTo flag for a non-concentration capped duration (\"Up to 1 minute\")."
      • changedInput schema / properties / forcedMovement / items / properties / requires / items / properties / armorCategories / description
        Previous value: -"For 'equipped' + slot:armor: armor category list (Light / Medium / Heavy). OR semantics — match any."New value: +"Armor categories to match, as the items' `armorCategory` values name them. OR semantics — match any."
      • changedInput schema / properties / forcedMovement / items / properties / requires / items / properties / condition / description
        Previous value: -"For 'condition' predicates: the character-state condition to gate on (5e24 named conditions and ongoing-action states)."New value: +"For 'condition' predicates: the character-state condition to gate on (named conditions and ongoing-action states)."
      • changedInput schema / properties / forcedMovement / items / properties / requires / items / properties / condition / enum
        Previous value: -[
        -  "blinded",
        -  "charmed",
        -  "dazed",
        -  "deafened",
        -  "exhaustion",
        -  "frightened",
        -  "grappled",
        -  "incapacitated",
        -  "invisible",
        -  "paralyzed",
        -  "petrified",
        -  "poisoned",
        -  "prone",
        -  "restrained",
        -  "stunned",
        -  "unconscious",
        -  "concentrating",
        -  "grappling",
        -  "dodging",
        -  "hiding",
        -  "raging"
        -]New value: +[
        +  "blinded",
        +  "charmed",
        +  "concentration",
        +  "deafened",
        +  "exhaustion",
        +  "frightened",
        +  "grappled",
        +  "incapacitated",
        +  "invisible",
        +  "paralyzed",
        +  "petrified",
        +  "poisoned",
        +  "prone",
        +  "restrained",
        +  "stunned",
        +  "unconscious",
        +  "dazed",
        +  "grappling",
        +  "dodging",
        +  "hiding",
        +  "raging"
        +]
      • changedInput schema / properties / forcedMovement / items / properties / requires / items / properties / equipSlot / description
        Previous value: -"Body slot the matched weapon must occupy. mainHand / offHand. Resolved via getRequiredSlots so two-handed grips occupy both."New value: +"Body slot the matched weapon must occupy (one of the schema's enum)."
      • changedInput schema / properties / forcedMovement / items / properties / requires / items / properties / slot / description
        Previous value: -"For 'equipped' predicates: the body category to match (armor / shield / weapon)."New value: +"The equipped body category to match (one of the schema's enum)."
      • changedInput schema / properties / forcedMovement / items / properties / requires / items / properties / type / description
        Previous value: -"Predicate type. 'equipped' = character-scoped (gates on what's equipped). 'attackingWeapon' = attack-scoped (gates on the current action's source weapon). 'condition' = gates on a character-state condition."New value: +"Predicate type (one of the schema's enum): what the predicate gates on."
      • changedInput schema / properties / forcedMovement / items / properties / requires / items / properties / weaponProperties / description
        Previous value: -"For 'equipped' + slot:weapon OR 'attackingWeapon': weapon-property list. AND semantics — match all."New value: +"Weapon properties to match. AND semantics — match all."
      • changedInput schema / properties / higherLevel / description
        Previous value: -"Higher-Level / cantrip-scaling text (what changes when cast with a higher slot)."New value: +"Scaling text: what changes when the spell is cast at a higher level or scales with the caster, source text."
      • changedInput schema / properties / level / description
        Previous value: -"Spell level. 0 for cantrips; 1–9 for leveled spells (5e/5e24)."New value: +"Spell level, within the schema's range. The spell authoring guide gives the convention."
      • changedInput schema / properties / level / maximum
        Previous value: -9007199254740991New value: +9
      • changedInput schema / properties / level / minimum
        Previous value: --9007199254740991New value: +0
      • changedInput schema / properties / prerequisites / items / properties / abilities / description
        Previous value: -"For abilityScore: ANY listed ability meeting `min` satisfies ('Str or Dex 13+')."New value: +"For abilityScore: ANY listed ability meeting `min` satisfies."
      • changedInput schema / properties / prerequisites / items / properties / proficiency / description
        Previous value: -"For proficiency: the proficiency name (e.g. 'Martial', 'Stealth')."New value: +"For proficiency: the proficiency name, as the ruleset names it."
      • changedInput schema / properties / prerequisites / items / properties / proficiencyType / enum
        Previous value: -[
        -  "skill",
        -  "tool",
        -  "weapon",
        -  "armor",
        -  "save",
        -  "language"
        -]New value: +[
        +  "skill",
        +  "tool",
        +  "save",
        +  "weapon",
        +  "armor",
        +  "language"
        +]
      • changedInput schema / properties / prerequisites / items / properties / type / description
        Previous value: -"Predicate kind: level / abilityScore / rule / spell / proficiency / spellcasting. (A class is required via a `rule` predicate pointing at the class rule.)"New value: +"Predicate kind. (A class is required via a `rule` predicate pointing at the class rule.)"
      • changedInput schema / properties / range / description
        Previous value: -"Range. kind ∈ self|touch|ranged|sight|unlimited|special; distance for ranged; unit ∈ feet|miles (default feet)."New value: +"Range. `kind`; `distance` and its `unit` for a ranged spell (absent unit = feet)."
      • changedInput schema / properties / rank / description
        Previous value: -"PFRPG2 rank field. Free-form."New value: +"Rank, for rulesets whose spells carry one. Free-form."
      • changedInput schema / properties / reactionTrigger / description
        Previous value: -"When castingTime.unit is 'reaction', the trigger text ('which you take when…')."New value: +"For a casting time taken in response to a trigger, the trigger text, source text."
      • changedInput schema / properties / recurringDamage / items / properties / requires / items / properties / armorCategories / description
        Previous value: -"For 'equipped' + slot:armor: armor category list (Light / Medium / Heavy). OR semantics — match any."New value: +"Armor categories to match, as the items' `armorCategory` values name them. OR semantics — match any."
      • changedInput schema / properties / recurringDamage / items / properties / requires / items / properties / condition / description
        Previous value: -"For 'condition' predicates: the character-state condition to gate on (5e24 named conditions and ongoing-action states)."New value: +"For 'condition' predicates: the character-state condition to gate on (named conditions and ongoing-action states)."
      • changedInput schema / properties / recurringDamage / items / properties / requires / items / properties / condition / enum
        Previous value: -[
        -  "blinded",
        -  "charmed",
        -  "dazed",
        -  "deafened",
        -  "exhaustion",
        -  "frightened",
        -  "grappled",
        -  "incapacitated",
        -  "invisible",
        -  "paralyzed",
        -  "petrified",
        -  "poisoned",
        -  "prone",
        -  "restrained",
        -  "stunned",
        -  "unconscious",
        -  "concentrating",
        -  "grappling",
        -  "dodging",
        -  "hiding",
        -  "raging"
        -]New value: +[
        +  "blinded",
        +  "charmed",
        +  "concentration",
        +  "deafened",
        +  "exhaustion",
        +  "frightened",
        +  "grappled",
        +  "incapacitated",
        +  "invisible",
        +  "paralyzed",
        +  "petrified",
        +  "poisoned",
        +  "prone",
        +  "restrained",
        +  "stunned",
        +  "unconscious",
        +  "dazed",
        +  "grappling",
        +  "dodging",
        +  "hiding",
        +  "raging"
        +]
      • changedInput schema / properties / recurringDamage / items / properties / requires / items / properties / equipSlot / description
        Previous value: -"Body slot the matched weapon must occupy. mainHand / offHand. Resolved via getRequiredSlots so two-handed grips occupy both."New value: +"Body slot the matched weapon must occupy (one of the schema's enum)."
      • changedInput schema / properties / recurringDamage / items / properties / requires / items / properties / slot / description
        Previous value: -"For 'equipped' predicates: the body category to match (armor / shield / weapon)."New value: +"The equipped body category to match (one of the schema's enum)."
      • changedInput schema / properties / recurringDamage / items / properties / requires / items / properties / type / description
        Previous value: -"Predicate type. 'equipped' = character-scoped (gates on what's equipped). 'attackingWeapon' = attack-scoped (gates on the current action's source weapon). 'condition' = gates on a character-state condition."New value: +"Predicate type (one of the schema's enum): what the predicate gates on."
      • changedInput schema / properties / recurringDamage / items / properties / requires / items / properties / weaponProperties / description
        Previous value: -"For 'equipped' + slot:weapon OR 'attackingWeapon': weapon-property list. AND semantics — match all."New value: +"Weapon properties to match. AND semantics — match all."
      • changedInput schema / properties / resistances / items / properties / range / description
        Previous value: -"Aura radius in feet for ally/any-targeted resistances (Warding Aura's 10 ft.). Absent = self-only."New value: +"Aura radius in feet for ally/any-targeted resistances. Absent = self-only."
      • changedInput schema / properties / ritual / description
        Previous value: -"5.5e ritual tag — the spell can be cast as a ritual (no spell slot)."New value: +"Ritual tag: the spell can be cast as a ritual."
      • changedInput schema / properties / rollMods / items / properties / requires / items / properties / armorCategories / description
        Previous value: -"For 'equipped' + slot:armor: armor category list (Light / Medium / Heavy). OR semantics — match any."New value: +"Armor categories to match, as the items' `armorCategory` values name them. OR semantics — match any."
      • changedInput schema / properties / rollMods / items / properties / requires / items / properties / condition / description
        Previous value: -"For 'condition' predicates: the character-state condition to gate on (5e24 named conditions and ongoing-action states)."New value: +"For 'condition' predicates: the character-state condition to gate on (named conditions and ongoing-action states)."
      • changedInput schema / properties / rollMods / items / properties / requires / items / properties / condition / enum
        Previous value: -[
        -  "blinded",
        -  "charmed",
        -  "dazed",
        -  "deafened",
        -  "exhaustion",
        -  "frightened",
        -  "grappled",
        -  "incapacitated",
        -  "invisible",
        -  "paralyzed",
        -  "petrified",
        -  "poisoned",
        -  "prone",
        -  "restrained",
        -  "stunned",
        -  "unconscious",
        -  "concentrating",
        -  "grappling",
        -  "dodging",
        -  "hiding",
        -  "raging"
        -]New value: +[
        +  "blinded",
        +  "charmed",
        +  "concentration",
        +  "deafened",
        +  "exhaustion",
        +  "frightened",
        +  "grappled",
        +  "incapacitated",
        +  "invisible",
        +  "paralyzed",
        +  "petrified",
        +  "poisoned",
        +  "prone",
        +  "restrained",
        +  "stunned",
        +  "unconscious",
        +  "dazed",
        +  "grappling",
        +  "dodging",
        +  "hiding",
        +  "raging"
        +]
      • changedInput schema / properties / rollMods / items / properties / requires / items / properties / equipSlot / description
        Previous value: -"Body slot the matched weapon must occupy. mainHand / offHand. Resolved via getRequiredSlots so two-handed grips occupy both."New value: +"Body slot the matched weapon must occupy (one of the schema's enum)."
      • changedInput schema / properties / rollMods / items / properties / requires / items / properties / slot / description
        Previous value: -"For 'equipped' predicates: the body category to match (armor / shield / weapon)."New value: +"The equipped body category to match (one of the schema's enum)."
      • changedInput schema / properties / rollMods / items / properties / requires / items / properties / type / description
        Previous value: -"Predicate type. 'equipped' = character-scoped (gates on what's equipped). 'attackingWeapon' = attack-scoped (gates on the current action's source weapon). 'condition' = gates on a character-state condition."New value: +"Predicate type (one of the schema's enum): what the predicate gates on."
      • changedInput schema / properties / rollMods / items / properties / requires / items / properties / weaponProperties / description
        Previous value: -"For 'equipped' + slot:weapon OR 'attackingWeapon': weapon-property list. AND semantics — match all."New value: +"Weapon properties to match. AND semantics — match all."
      • changedInput schema / properties / ruleset / description
        Previous value: -"Ruleset code (e.g. '5th Edition', '5e24', 'PFRPG', 'Savage Worlds')."New value: +"Ruleset code, from list_rulesets."
      • changedInput schema / properties / school / description
        Previous value: -"Spell school (Abjuration, Conjuration, Divination, Enchantment, Evocation, Illusion, Necromancy, Transmutation)."New value: +"Spell school name."
      • changedInput schema / properties / statBonuses / items / properties / durationCount / description
        Previous value: -"Numeric count paired with durationUnit (e.g. count: 3, unit: 'round')."New value: +"Numeric count paired with durationUnit."
      • changedInput schema / properties / statBonuses / items / properties / range / description
        Previous value: -"Aura radius in feet for ally/any-audience bonuses (Aura of Protection's 10 ft.). Absent = no range filter."New value: +"Aura radius in feet for ally/any-audience bonuses. Absent = no range filter."
      • changedInput schema / properties / statBonuses / items / properties / requires / items / properties / armorCategories / description
        Previous value: -"For 'equipped' + slot:armor: armor category list (Light / Medium / Heavy). OR semantics — match any."New value: +"Armor categories to match, as the items' `armorCategory` values name them. OR semantics — match any."
      • changedInput schema / properties / statBonuses / items / properties / requires / items / properties / condition / description
        Previous value: -"For 'condition' predicates: the character-state condition to gate on (5e24 named conditions and ongoing-action states)."New value: +"For 'condition' predicates: the character-state condition to gate on (named conditions and ongoing-action states)."
      • changedInput schema / properties / statBonuses / items / properties / requires / items / properties / condition / enum
        Previous value: -[
        -  "blinded",
        -  "charmed",
        -  "dazed",
        -  "deafened",
        -  "exhaustion",
        -  "frightened",
        -  "grappled",
        -  "incapacitated",
        -  "invisible",
        -  "paralyzed",
        -  "petrified",
        -  "poisoned",
        -  "prone",
        -  "restrained",
        -  "stunned",
        -  "unconscious",
        -  "concentrating",
        -  "grappling",
        -  "dodging",
        -  "hiding",
        -  "raging"
        -]New value: +[
        +  "blinded",
        +  "charmed",
        +  "concentration",
        +  "deafened",
        +  "exhaustion",
        +  "frightened",
        +  "grappled",
        +  "incapacitated",
        +  "invisible",
        +  "paralyzed",
        +  "petrified",
        +  "poisoned",
        +  "prone",
        +  "restrained",
        +  "stunned",
        +  "unconscious",
        +  "dazed",
        +  "grappling",
        +  "dodging",
        +  "hiding",
        +  "raging"
        +]
      • changedInput schema / properties / statBonuses / items / properties / requires / items / properties / equipSlot / description
        Previous value: -"Body slot the matched weapon must occupy. mainHand / offHand. Resolved via getRequiredSlots so two-handed grips occupy both."New value: +"Body slot the matched weapon must occupy (one of the schema's enum)."
      • changedInput schema / properties / statBonuses / items / properties / requires / items / properties / slot / description
        Previous value: -"For 'equipped' predicates: the body category to match (armor / shield / weapon)."New value: +"The equipped body category to match (one of the schema's enum)."
      • changedInput schema / properties / statBonuses / items / properties / requires / items / properties / type / description
        Previous value: -"Predicate type. 'equipped' = character-scoped (gates on what's equipped). 'attackingWeapon' = attack-scoped (gates on the current action's source weapon). 'condition' = gates on a character-state condition."New value: +"Predicate type (one of the schema's enum): what the predicate gates on."
      • changedInput schema / properties / statBonuses / items / properties / requires / items / properties / weaponProperties / description
        Previous value: -"For 'equipped' + slot:weapon OR 'attackingWeapon': weapon-property list. AND semantics — match all."New value: +"Weapon properties to match. AND semantics — match all."
      • changedInput schema / properties / statBonuses / items / properties / target / description
        Previous value: -"Stat the bonus contributes to (e.g. 'skills.Acrobatics.misc', 'attributes.strength.misc')."New value: +"Stat the bonus contributes to (e.g. 'skills.<skill>.misc', 'attributes.<ability>.misc')."
      • changedInput schema / properties / statBonuses / items / properties / trigger / description
        Previous value: -"Action-economy / cost shape of the bonus. passive / toggled / reaction / perRoll / resource / targetBound."New value: +"Action-economy / cost shape of the bonus."
      • changedInput schema / properties / statBonuses / items / properties / triggerEvent / description
        Previous value: -"Game-time event that fires the bonus (onHit / onDamage / startOfYourTurn / etc.). Absent = not event-driven (passive walker contributes whenever `requires` holds)."New value: +"Game-time event that fires the bonus (one of the schema's trigger events). Absent = not event-driven (passive walker contributes whenever `requires` holds)."
      • changedInput schema / properties / statBonuses / items / properties / valueType / enum
        Previous value: -[
        -  "fixed",
        -  "attribute",
        -  "proficiency",
        -  "level",
        -  "halfLevel",
        -  "dice",
        -  "byLevel",
        -  "attackAttribute"
        -]New value: +[
        +  "fixed",
        +  "attribute",
        +  "attackAttribute",
        +  "proficiency",
        +  "level",
        +  "halfLevel",
        +  "dice",
        +  "byLevel"
        +]
      • changedInput schema / properties / type / description
        Previous value: -"Spell type. 5e / 5e24 use 'Spell'; Savage Worlds uses 'Power'. Required at create."New value: +"Spell type (the ruleset's name for a spell). Required at create."
    • Changedvault_get_authoring_guide2 fields changed
      • changedInput schema / properties / entityType / description
        Previous value: -"Entity the guide covers. Published for 5e24: 'monster', 'rule' (classes / species / backgrounds / feats / abilities), and 'spell'. Other entity types and rulesets land as separate guides over time. Lowercase."New value: +"Entity the guide covers: 'monster', 'rule' (classes / species / backgrounds / feats / abilities), or 'spell'. Lowercase. A ruleset / entity pair with no published guide returns not found."
      • changedInput schema / properties / rulesetCode / description
        Previous value: -"Ruleset data value (e.g. '5th Edition', '5e24', 'PFRPG', 'PFRPG2', 'PF Playtest', 'Savage Worlds', 'Savage Embers', 'Solarian Conflict', 'Embers RPG'). Use the data value, not the display label."New value: +"Ruleset code, from list_rulesets. Use the code, not the display label."
    • Changedvault_get_levelup_options1 field changed
      • changedInput schema / properties / classRuleId / description
        Previous value: -"Omit for the CHOOSER (the character's class entries with their stored levels, the multiclass candidates with warn-only prerequisite warnings, the XP floor for the next level, atMaxLevel). Supply a base Class rule `_id` — one of the chooser's `classEntries[].classRuleId` to advance a held class, or a `multiclassOptions[]._id` to enter a new class at level 1 — for the TARGET PLAN: `features[]` / `subclassFeatures[]` / `growth[]` (each feature in the creation option shape with its open choice blocks: `choice` {label,count,options}, spellChoices (each block carries `prepared` — true = its spells land always-prepared and are EXCLUDED from the preparedSpellPicks pool), spellListChoices (same `prepared` flag), preparedSpells, proficiencyChoices, abilityScoreBump; `growth[]` entries are already-held rules whose counts grew this level — their `count`s are DELTAS, \"pick N more\"), `multiclassGrants` (when entering a new class), `hitPoints` {hitDie, average, conModifier}, `prerequisiteWarnings[]` (warn-only), `spellSlots` (the combined multiclass pool preview, null unless 2+ contributing casters), `openPickCount`, and `xp` {current, minimumForNewTotal}. ruleChoice pools arrive PREREQUISITE-FILTERED (an unqualified pick is also rejected on apply)."New value: +"Omit for the CHOOSER (the character's class entries with their stored levels, the multiclass candidates with warn-only prerequisite warnings, the XP floor for the next level, atMaxLevel). Supply a base Class rule `_id` — one of the chooser's `classEntries[].classRuleId` to advance a held class, or a `multiclassOptions[]._id` to enter a new class — for the TARGET PLAN: `features[]` / `subclassFeatures[]` / `growth[]` (each feature in the creation option shape with its open choice blocks: `choice` {label,count,options}, spellChoices (each block carries `prepared` — true = its spells land always-prepared and are EXCLUDED from the preparedSpellPicks pool), spellListChoices (same `prepared` flag), preparedSpells, proficiencyChoices, abilityScoreBump; `growth[]` entries are already-held rules whose counts grew this level — their `count`s are DELTAS, \"pick N more\"), `multiclassGrants` (when entering a new class), `hitPoints` {hitDie, average, conModifier}, `prerequisiteWarnings[]` (warn-only), `spellSlots` (the combined multiclass pool preview, null when the plan has no combined pool), `openPickCount`, and `xp` {current, minimumForNewTotal}. ruleChoice pools arrive PREREQUISITE-FILTERED (an unqualified pick is also rejected on apply)."
    • Changedvault_get_pc_creation_options2 fields changed
      • changedInput schema / properties / kind / description
        Previous value: -"Which 5e24 creation list to read. 'class' / 'species' / 'background' / 'feat' return the option projections (the user's own + stock content they may pick, with each option's nested choices — skillChoices, toolChoices, startingEquipmentOptions, and per applied ability/feat: proficiencyChoices {types,count,options}, spellChoices {count,options,prepared}, spellListChoices {categories,picks[].optionsByCategory,prepared}, preparedSpells {count} (a block's `prepared: true` = its spells land always-prepared and are EXCLUDED from the preparedSpellPicks pool), abilityScoreBump {options[].lines[]:{amount,count,eligible,max}} (supply the player's pick via `vault_build_pc.abilityBumpPicks`), and `choice` {count,options} where each option carries a `type`. The spellChoices / spellListChoices arrays are INDEX-ALIGNED with the authored blocks — a null entry holds the position of a block that grants nothing at level 1; skip it when rendering but count it when keying picks. A 'background' option ALSO carries its own `skillChoices {count,options}` (a background skill-choice grant → supply picks via `vault_build_pc.backgroundSkillProficiencies`) and `languages {fixed, choose:{count,options}}`; a 'species' option carries `languages {fixed, choose}`. For a `languages.choose` grant, supply the picks via `vault_build_pc.languageChoicePicks` keyed by that rule's `_id`; `languages.fixed` apply automatically). 'feat' returns EVERY feat (the background slot uses Origin-category feats; a feat picked via an ability's `choice` may be any) — a picked feat carries its own proficiency/spell sub-choices. Each 'feat' option carries `repeatable`; a `repeatable` feat filling the background slot keys its `vault_build_pc` picks with a `bg:` prefix. 'constants' returns the static reference data (skill list, ability-score methods and their arrays/point-buy costs, language options, alignments, background bump modes, max ability score, and originFeatCategory — the feat category the background's open feat slot is restricted to; filter the 'feat' list to it for the background pick). Read 'constants' plus 'class' first; read 'species'/'background'/'feat' as the build takes shape."New value: +"Which creation list to read. 'class' / 'species' / 'background' / 'feat' return the option projections (the user's own + stock content they may pick, with each option's nested choices — skillChoices, toolChoices, startingEquipmentOptions, and per applied ability/feat: proficiencyChoices {types,count,options}, spellChoices {count,options,prepared}, spellListChoices {categories,picks[].optionsByCategory,prepared}, preparedSpells {count} (a block's `prepared: true` = its spells land always-prepared and are EXCLUDED from the preparedSpellPicks pool), abilityScoreBump {options[].lines[]:{amount,count,eligible,max}} (supply the player's pick via `vault_build_pc.abilityBumpPicks`), and `choice` {count,options} where each option carries a `type`. The spellChoices / spellListChoices arrays are INDEX-ALIGNED with the authored blocks — a null entry holds the position of a block that grants nothing at the starting level; skip it when rendering but count it when keying picks. A 'background' option ALSO carries its own `skillChoices {count,options}` (a background skill-choice grant → supply picks via `vault_build_pc.backgroundSkillProficiencies`) and `languages {fixed, choose:{count,options}}`; a 'species' option carries `languages {fixed, choose}`. For a `languages.choose` grant, supply the picks via `vault_build_pc.languageChoicePicks` keyed by that rule's `_id`; `languages.fixed` apply automatically). 'feat' returns EVERY feat (the background slot uses the `originFeatCategory` feats; a feat picked via an ability's `choice` may be any) — a picked feat carries its own proficiency/spell sub-choices. Each 'feat' option carries `repeatable`; a `repeatable` feat filling the background slot keys its `vault_build_pc` picks with a `bg:` prefix. 'constants' returns the static reference data (skill list, ability-score methods and each method's data, language options, alignments, background bump modes, max ability score, and originFeatCategory — the feat category the background's open feat slot is restricted to; filter the 'feat' list to it for the background pick). Read 'constants' plus 'class' first; read 'species'/'background'/'feat' as the build takes shape."
      • addedInput schema / properties / ruleset
        Added value: +{
        +  "description": "A ruleset with guided character creation. Send the same ruleset to `vault_build_pc`.",
        +  "enum": [
        +    "5e24"
        +  ],
        +  "type": "string"
        +}
    • Changedvault_level_up_pc6 fields changed
      • changedInput schema / properties / abilityBumpPicks / description
        Previous value: -"Ability-score-increase picks for a gained rule carrying an `abilityScoreBump` (the ASI feat picked at level 4+): `{ option, lines }` keyed by the granting rule's `_id`, same shape as `vault_build_pc`. A Constitution increase raises HP retroactively for every level already held."New value: +"Ability-score-increase picks for a gained rule carrying an `abilityScoreBump`: `{ option, lines }` keyed by the granting rule's `_id`, same shape as `vault_build_pc`. The engine applies whatever the increase changes elsewhere on the sheet."
      • changedInput schema / properties / abilityChoices / description
        Previous value: -"ruleChoice picks, keyed by the OWNING rule's `_id`: a gained feature's choice (a Fighting Style; the class's subclass-choice ability at level 3 — value = the picked subclass `_id`; an ASI ability — value = the picked feat `_id`) AND a grown held rule's choice (`growth[]` entries, e.g. new invocations — supply the NEW picks only, the delta count). A picked option's own sub-choices (a feat's skill picks, its abilityScoreBump) go in the other maps keyed by the picked option's `_id`, exactly as in `vault_build_pc`. Pools are prerequisite-filtered; an unqualified pick rejects the draft."New value: +"ruleChoice picks, keyed by the OWNING rule's `_id`: a gained feature's choice (the class's subclass-choice ability — value = the picked subclass `_id`; a choice among feats — value = the picked feat `_id`) AND a grown held rule's choice (`growth[]` entries — supply the NEW picks only, the delta count). A picked option's own sub-choices (a feat's skill picks, its abilityScoreBump) go in the other maps keyed by the picked option's `_id`, exactly as in `vault_build_pc`. Pools are prerequisite-filtered; an unqualified pick rejects the draft."
      • changedInput schema / properties / classRuleId / description
        Previous value: -"Required. The base Class rule to advance one level — a held class entry (its stored level bumps) or a class the character doesn't hold yet (multiclass: a second class entry is stamped at level 1). From the chooser's `classEntries[].classRuleId` / `multiclassOptions[]._id`."New value: +"Required. The base Class rule to advance one level — a held class entry (its stored level bumps) or a class the character doesn't hold yet (multiclass: a new class entry is stamped). From the chooser's `classEntries[].classRuleId` / `multiclassOptions[]._id`."
      • changedInput schema / properties / hitPoints / description
        Previous value: -"How the level's hit points are gained: `{method:'average'}` takes the fixed average (the plan's `hitPoints.average`); `{method:'roll', value}` records a die the PLAYER rolled — value must be 1..the class's hit die. The Constitution modifier is added server-side either way."New value: +"How the level's hit points are gained: `method` is one of the schema's methods (the plan's `hitPoints` fields carry what each one uses); `value` is a die the PLAYER rolled, for a method that takes one."
      • changedInput schema / properties / proficiencyChoicePicks / description
        Previous value: -"Picks for proficiencyChoices grants on gained/grown rules, keyed `\"<ruleId>:<grantIndex>\"` — same keying and rules as `vault_build_pc`. Grown grants demand only the DELTA count the plan surfaced. An EXPERTISE grant's pool is the character's proficient skills MINUS those that already carry Expertise (narrowed to the grant's own options for mode 'specific'); when that pool is at/below the count, vault auto-grants and expects NO picks."New value: +"Picks for proficiencyChoices grants on gained/grown rules, keyed `\"<ruleId>:<grantIndex>\"` — same keying and rules as `vault_build_pc`. Grown grants demand only the DELTA count the plan surfaced. An EXPERTISE grant picks from the pool the rule authoring guide describes (vault_get_authoring_guide, entityType .rule., proficiencyChoices); vault rejects picks that do not fit."
      • changedInput schema / properties / spellListChoicePicks / description
        Previous value: -"Picks for a NEWLY gained rule's spellListChoices (the Magic Initiate shape) — `{ category, picks, castingAbility? }` keyed `\"<ruleId>:<blockIndex>\"`, exactly as in `vault_build_pc`."New value: +"Picks for a NEWLY gained rule's spellListChoices — `{ category, picks, castingAbility? }` keyed `\"<ruleId>:<blockIndex>\"`, exactly as in `vault_build_pc`."
    • Changedvault_search_characters1 field changed
      • changedInput schema / properties / ruleset / description
        Previous value: -"Ruleset code (e.g. '5th Edition', '5e24', 'PFRPG', 'Savage Worlds', 'Universal')."New value: +"Ruleset code, from list_rulesets."
    • Changedvault_search_items2 fields changed
      • changedInput schema / properties / ruleset / description
        Previous value: -"Ruleset code (e.g. '5th Edition', '5e24', 'PFRPG', 'Savage Worlds', 'Universal')."New value: +"Ruleset code, from list_rulesets."
      • changedInput schema / properties / type / description
        Previous value: -"Item type (substring, case-insensitive). Vault item types are ruleset-specific strings. Common 5e / 5e24 examples: 'Weapon', 'Armor', 'Tool', 'Adventuring Gear', 'Wondrous Item'."New value: +"Item type (substring, case-insensitive). Vault item types are ruleset-specific strings; an unfiltered search shows the types a ruleset's catalog uses."
    • Changedvault_search_monsters1 field changed
      • changedInput schema / properties / ruleset / description
        Previous value: -"Ruleset code (e.g. '5th Edition', '5e24', 'PFRPG', 'Savage Worlds', 'Universal')."New value: +"Ruleset code, from list_rulesets."
    • Changedvault_search_rules2 fields changed
      • changedInput schema / properties / ruleset / description
        Previous value: -"Ruleset code (e.g. '5th Edition', '5e24', 'PFRPG', 'Savage Worlds', 'Universal')."New value: +"Ruleset code, from list_rulesets."
      • changedInput schema / properties / type / enum
        Previous value: -[
        -  "Ability",
        -  "Feat",
        -  "Action Card",
        -  "Hindrance",
        -  "Edge",
        -  "Class",
        -  "Background",
        -  "Race",
        -  "Species",
        -  "Ancestry",
        -  "Glossary",
        -  "Stunt",
        -  "Extra"
        -]New value: +[
        +  "Ability",
        +  "Feat",
        +  "Glossary",
        +  "Action Card",
        +  "Hindrance",
        +  "Edge",
        +  "Class",
        +  "Background",
        +  "Race",
        +  "Species",
        +  "Ancestry",
        +  "Stunt",
        +  "Extra"
        +]
    • Changedvault_search_spells2 fields changed
      • changedInput schema / properties / ruleset / description
        Previous value: -"Ruleset code (e.g. '5th Edition', '5e24', 'PFRPG', 'Savage Worlds', 'Universal')."New value: +"Ruleset code, from list_rulesets."
      • changedInput schema / properties / type / description
        Previous value: -"Spell type. 5e / 5e24 use 'Spell'; Savage Worlds uses 'Power'."New value: +"Spell type (the ruleset's name for a spell)."
    • Changedvault_spawn_linked_character1 field changed
      • changedInput schema / properties / ruleset / description
        Previous value: -"Ruleset code for the new linked sheet (e.g. '5th Edition', '5e24', 'Fate Core'). Required. Must differ from the source's ruleset; restricted rulesets require an entitlement grant (vault answers 403). Check list_rulesets for the codes this account can use."New value: +"Ruleset code for the new linked sheet, from list_rulesets (the codes this account can use). Required. Must differ from the source's ruleset; restricted rulesets require an entitlement grant (vault answers 403)."
    • Changedvault_update_character46 fields changed
      • changedInput schema / properties / actions / items / properties / actions / description
        Previous value: -"PF Playtest action-economy marker (F/1/2/3/R)."New value: +"Action-cost marker, for rulesets whose actions carry one; the value is the source text."
      • changedInput schema / properties / actions / items / properties / attack / properties / attribute / description
        Previous value: -"Ability driving the to-hit roll (e.g. 'strength', 'charisma' for spell attacks)."New value: +"Ability driving the to-hit roll."
      • changedInput schema / properties / actions / items / properties / rof / description
        Previous value: -"Savage Worlds Rate of Fire."New value: +"Rate of fire, for rulesets whose actions carry one."
      • changedInput schema / properties / actions / items / properties / type / description
        Previous value: -"Action type. 5e24 uses 'Melee' / 'Range' / 'Special' / 'Reaction' / 'Legendary' / 'Bonus'."New value: +"Action type, as the ruleset's sheet names it."
      • changedInput schema / properties / aspects / items / properties / kind / description
        Previous value: -"One of 'high concept', 'trouble', 'character', 'consequence'."New value: +"The aspect's kind. The values are the ones the ruleset's sheet template uses; read a character of that ruleset (vault_get_character) to see them."
      • changedInput schema / properties / aspects / items / properties / shifts / description
        Previous value: -"Consequence/condition slots only: harm absorbed. Fate: 2 Mild, 4 Moderate, 6 Severe, 8 Extreme (Fate Accelerated omits Extreme). Demon Hunters conditions: 5 Mild, 10 Moderate, 15 Severe."New value: +"Consequence/condition slots only: the harm the slot absorbs, as the ruleset's sheet template sets it per slot."
      • changedInput schema / properties / attributes / items / properties / misc / description
        Previous value: -"Misc bonus on the save (5e/5e24). Used for high-PB monster compensation."New value: +"Misc bonus on the save. The monster authoring guide covers when a monster uses it."
      • changedInput schema / properties / attributes / items / properties / name / description
        Previous value: -"Ability name: strength / dexterity / constitution / intelligence / wisdom / charisma. Lowercase."New value: +"Ability id, lowercase (a value from the abilities list the typed tools' schemas carry)."
      • changedInput schema / properties / attributes / items / properties / proficient / description
        Previous value: -"Save proficiency flag (5e/5e24). When true, PB is added to the save."New value: +"Save proficiency flag. The sheet applies it to the save total."
      • changedInput schema / properties / attributes / items / properties / score / description
        Previous value: -"Raw ability score (e.g. 17). Modifier is derived by the sheet."New value: +"Raw ability score. Modifier is derived by the sheet."
      • changedInput schema / properties / core / properties / race / description
        Previous value: -"Creature type for monsters (e.g. 'Elemental', 'Humanoid', 'Dragon (Chromatic)'); race for PCs."New value: +"Creature type for monsters (source text); race for PCs."
      • changedInput schema / properties / core / properties / refresh / description
        Previous value: -"Session-start resource: fate points (Fate — Refresh) or faith dice (Demon Hunters — Devotion). The total the character resets to at the start of a session."New value: +"Session-start resource: the total the character resets to at the start of a session. The sheet template of the character's ruleset labels it."
      • changedInput schema / properties / core / properties / size / description
        Previous value: -"Creature size. Exact source text including 'or' for variable sizes ('Medium or Small')."New value: +"Creature size. Exact source text including 'or' for variable sizes ('X or Y')."
      • changedInput schema / properties / defense / properties / armorClass / description
        Previous value: -"Layered AC rows the sheet sums. IMPORTANT (5e24): when the character's `settings.autoPassiveBonuses` is true — the default for new 5e24 characters — the `armor` and `shield` rows are DERIVED from equipped items and recomputed on every sheet load, so writing them here gets overwritten. Change AC by setting `equipped: true/false` on the character's armor/shield items instead. When the toggle is false (and on all other rulesets), these rows are manually authored and writing them here is correct. `magic` and `misc` are manual in both modes. Check the toggle with vault_get_character before writing."New value: +"Layered AC rows the sheet sums. IMPORTANT: when the character's `settings.autoPassiveBonuses` is true — the default for new characters in rulesets with sheet automation — the `armor` and `shield` rows are DERIVED from equipped items and recomputed on every sheet load, so writing them here gets overwritten. Change AC by setting `equipped: true/false` on the character's armor/shield items instead. When the toggle is false (and on rulesets without sheet automation), these rows are manually authored and writing them here is correct. `magic` and `misc` are manual in both modes. Check the toggle with vault_get_character before writing."
      • changedInput schema / properties / defense / properties / armorClass / properties / armor / properties / bonus / description
        Previous value: -"Base AC value the sheet adds DEX to. See the 5e24 monster guide Rule 1 for the math."New value: +"Base AC value the sheet builds the total from. The monster authoring guide's Rule 1 gives the math."
      • changedInput schema / properties / defense / properties / armorClass / properties / armor / properties / description / description
        Previous value: -"Armor name ('Natural Armor', 'Chain Shirt') or null when AC derives from DEX only."New value: +"Armor name, source text, or null when no armor applies."
      • changedInput schema / properties / defense / properties / armorClass / properties / armor / properties / heavy / description
        Previous value: -"True suppresses DEX contribution entirely (heavy armor)."New value: +"True for heavy armor; the engine applies that armor weight's rule to the total."
      • changedInput schema / properties / defense / properties / armorClass / properties / armor / properties / medium / description
        Previous value: -"True caps DEX contribution to +2 (medium armor)."New value: +"True for medium armor; the engine applies that armor weight's rule to the total."
      • changedInput schema / properties / defense / properties / exhaustion / description
        Previous value: -"5e24 Exhaustion level (0-6). Absent = 0 (not exhausted). Each level is -2 to d20 Tests and -5 ft Speed; level 6 = death. A Long Rest via the vault rest control reduces it by 1."New value: +"Exhaustion level, within the schema's range. Absent = not exhausted. The engine applies its effects and reduces it on a rest taken through the vault rest control."
      • changedInput schema / properties / defense / properties / hitDice / properties / current / description
        Previous value: -"Unspent hit dice count. When `pools` is present (5e24 class characters), this is the derived sum of pool currents — keep it consistent with pools on write."New value: +"Unspent hit dice count. When `pools` is present, this is the derived sum of pool currents — keep it consistent with pools on write."
      • changedInput schema / properties / defense / properties / hitDice / properties / dice / description
        Previous value: -"Without `pools` (monsters, non-5e24): per-die expression, NOT the multiplied total — size-mapped Tiny d4 / Small d6 / Medium d8 / Large d10 / Huge d12 / Gargantuan d20, see monster guide Rule 20. When `pools` is present (5e24 class characters): the derived compound string ('5d10 + 5d6') — keep it consistent with pools on write."New value: +"Without `pools` (monsters, and sheets without pools): one die expression ('1dX'), NOT the multiplied total; the monster guide's Rule 20 gives a monster's die. When `pools` is present: the derived compound string, one 'NdX' term per pool joined by ' + ' — keep it consistent with pools on write."
      • changedInput schema / properties / defense / properties / hitDice / properties / pools / description
        Previous value: -"5e24 per-die-size Hit Dice pools — the AUTHORITATIVE representation (one entry per die size a multiclass character has). Maintained by creation, level-up, and a one-shot backfill; player edits win. The server does NOT re-derive the legacy fields on write, so when writing hit dice for a character with pools, write pools AND the legacy current/dice consistently (current = sum of pool currents; dice = compound string)."New value: +"Per-die-size Hit Dice pools, present on class characters the creation and level-up tools maintain — the AUTHORITATIVE representation (one entry per die size a multiclass character has). Maintained by creation, level-up, and a one-shot backfill; player edits win. The server does NOT re-derive the legacy fields on write, so when writing hit dice for a character with pools, write pools AND the legacy current/dice consistently (current = sum of pool currents; dice = compound string)."
      • changedInput schema / properties / defense / properties / hitDice / properties / pools / items / properties / dice / description
        Previous value: -"Die size of this pool, e.g. 'd10'."New value: +"Die size of this pool."
      • changedInput schema / properties / items / items / properties / sourceSpell / description
        Previous value: -"Auto-managed. Link to the spell that manufactured this companion armor item (e.g. Mage Armor, which the vault sheet offers as an equippable Light armor). The sheet sets and maintains it; if it's present on an item you're editing, preserve it verbatim, and never set, change, or invent it. Dropping it on a round-trip de-links the companion and leaves a duplicate item on the sheet."New value: +"Auto-managed. Link to the spell that manufactured this companion armor item (a spell the vault sheet offers as equippable armor). The sheet sets and maintains it; if it's present on an item you're editing, preserve it verbatim, and never set, change, or invent it. Dropping it on a round-trip de-links the companion and leaves a duplicate item on the sheet."
      • changedInput schema / properties / offense / properties / initiative / properties / attribute / description
        Previous value: -"Ability whose modifier drives initiative. Typically 'dexterity'."New value: +"Ability whose modifier drives initiative, lowercase."
      • changedInput schema / properties / rules / items / properties / statBonuses / items / properties / durationCount / description
        Previous value: -"Numeric count paired with durationUnit (e.g. count: 3, unit: 'round')."New value: +"Numeric count paired with durationUnit."
      • changedInput schema / properties / rules / items / properties / statBonuses / items / properties / range / description
        Previous value: -"Aura radius in feet for ally/any-audience bonuses (Aura of Protection's 10 ft.). Absent = no range filter."New value: +"Aura radius in feet for ally/any-audience bonuses. Absent = no range filter."
      • changedInput schema / properties / rules / items / properties / statBonuses / items / properties / requires / items / properties / armorCategories / description
        Previous value: -"For 'equipped' + slot:armor: armor category list (Light / Medium / Heavy). OR semantics — match any."New value: +"Armor categories to match, as the items' `armorCategory` values name them. OR semantics — match any."
      • changedInput schema / properties / rules / items / properties / statBonuses / items / properties / requires / items / properties / condition / description
        Previous value: -"For 'condition' predicates: the character-state condition to gate on (5e24 named conditions and ongoing-action states)."New value: +"For 'condition' predicates: the character-state condition to gate on (named conditions and ongoing-action states)."
      • changedInput schema / properties / rules / items / properties / statBonuses / items / properties / requires / items / properties / condition / enum
        Previous value: -[
        -  "blinded",
        -  "charmed",
        -  "dazed",
        -  "deafened",
        -  "exhaustion",
        -  "frightened",
        -  "grappled",
        -  "incapacitated",
        -  "invisible",
        -  "paralyzed",
        -  "petrified",
        -  "poisoned",
        -  "prone",
        -  "restrained",
        -  "stunned",
        -  "unconscious",
        -  "concentrating",
        -  "grappling",
        -  "dodging",
        -  "hiding",
        -  "raging"
        -]New value: +[
        +  "blinded",
        +  "charmed",
        +  "concentration",
        +  "deafened",
        +  "exhaustion",
        +  "frightened",
        +  "grappled",
        +  "incapacitated",
        +  "invisible",
        +  "paralyzed",
        +  "petrified",
        +  "poisoned",
        +  "prone",
        +  "restrained",
        +  "stunned",
        +  "unconscious",
        +  "dazed",
        +  "grappling",
        +  "dodging",
        +  "hiding",
        +  "raging"
        +]
      • changedInput schema / properties / rules / items / properties / statBonuses / items / properties / requires / items / properties / equipSlot / description
        Previous value: -"Body slot the matched weapon must occupy. mainHand / offHand. Resolved via getRequiredSlots so two-handed grips occupy both."New value: +"Body slot the matched weapon must occupy (one of the schema's enum)."
      • changedInput schema / properties / rules / items / properties / statBonuses / items / properties / requires / items / properties / slot / description
        Previous value: -"For 'equipped' predicates: the body category to match (armor / shield / weapon)."New value: +"The equipped body category to match (one of the schema's enum)."
      • changedInput schema / properties / rules / items / properties / statBonuses / items / properties / requires / items / properties / type / description
        Previous value: -"Predicate type. 'equipped' = character-scoped (gates on what's equipped). 'attackingWeapon' = attack-scoped (gates on the current action's source weapon). 'condition' = gates on a character-state condition."New value: +"Predicate type (one of the schema's enum): what the predicate gates on."
      • changedInput schema / properties / rules / items / properties / statBonuses / items / properties / requires / items / properties / weaponProperties / description
        Previous value: -"For 'equipped' + slot:weapon OR 'attackingWeapon': weapon-property list. AND semantics — match all."New value: +"Weapon properties to match. AND semantics — match all."
      • changedInput schema / properties / rules / items / properties / statBonuses / items / properties / target / description
        Previous value: -"Stat the bonus contributes to (e.g. 'skills.Acrobatics.misc', 'attributes.strength.misc')."New value: +"Stat the bonus contributes to (e.g. 'skills.<skill>.misc', 'attributes.<ability>.misc')."
      • changedInput schema / properties / rules / items / properties / statBonuses / items / properties / trigger / description
        Previous value: -"Action-economy / cost shape of the bonus. passive / toggled / reaction / perRoll / resource / targetBound."New value: +"Action-economy / cost shape of the bonus."
      • changedInput schema / properties / rules / items / properties / statBonuses / items / properties / triggerEvent / description
        Previous value: -"Game-time event that fires the bonus (onHit / onDamage / startOfYourTurn / etc.). Absent = not event-driven (passive walker contributes whenever `requires` holds)."New value: +"Game-time event that fires the bonus (one of the schema's trigger events). Absent = not event-driven (passive walker contributes whenever `requires` holds)."
      • changedInput schema / properties / rules / items / properties / statBonuses / items / properties / valueType / enum
        Previous value: -[
        -  "fixed",
        -  "attribute",
        -  "proficiency",
        -  "level",
        -  "halfLevel",
        -  "dice",
        -  "byLevel",
        -  "attackAttribute"
        -]New value: +[
        +  "fixed",
        +  "attribute",
        +  "attackAttribute",
        +  "proficiency",
        +  "level",
        +  "halfLevel",
        +  "dice",
        +  "byLevel"
        +]
      • changedInput schema / properties / rules / items / properties / type / description
        Previous value: -"Rule type (Ability / Feat / Class / Background / etc.). Vault validates against its rulestype enum on save."New value: +"Rule type. Vault validates it on save."
      • changedInput schema / properties / ruleset / description
        Previous value: -"Ruleset code (e.g. '5th Edition', '5e24', 'PFRPG', 'Savage Worlds'). Restricted rulesets require an entitlement grant on the account — vault answers 403 for ungranted or unknown codes. Check list_rulesets for the codes this account can use."New value: +"Ruleset code, from list_rulesets (the codes this account can use). Restricted rulesets require an entitlement grant on the account — vault answers 403 for ungranted or unknown codes."
      • changedInput schema / properties / settings / properties / autoPassiveBonuses / description
        Previous value: -"When true, the per-character rules engine layer contributes statBonuses from rules / items / feats. On 5e24 it ALSO derives the armor/shield rows of defense.armorClass from equipped items, recomputed on every sheet load — manual writes to those rows do not stick while this is true. Monsters should set this to false."New value: +"When true, the per-character rules engine layer contributes statBonuses from rules / items / feats. On rulesets with sheet automation it ALSO derives the armor/shield rows of defense.armorClass from equipped items, recomputed on every sheet load — manual writes to those rows do not stick while this is true. Monsters should set this to false."
      • changedInput schema / properties / settings / properties / hiddenSections / description
        Previous value: -"Sheet-section keys the player chose to hide while the section is empty ('spells', 'abilities', 'feats', 'origin', 'actionCards', 'hindrances', 'edges', 'stunts', 'extras'). A section with content always renders regardless of this list — the preference means 'hide when empty', never 'hide my data'."New value: +"Keys of the character sheet's sections the player chose to hide while the section is empty. A section with content always renders regardless of this list — the preference means 'hide when empty', never 'hide my data'."
      • changedInput schema / properties / skills / items / properties / rating / description
        Previous value: -"Fate: ladder position, -2 (Terrible) to +8 (Legendary); also an FAE approach's rating. Demon Hunters: the trait's die size (4, 6, 8, 10, or 12), or 0 for an unrated Fringe discipline."New value: +"The rating, on the ruleset's own scale. The ruleset's sheet template sets it; read a character of that ruleset (vault_get_character) to see the values."
      • changedInput schema / properties / spells / items / properties / recovery / description
        Previous value: -"Per-rest recovery rows for a finite free-cast counter, stamped from the granting rule's freeCast.recovery whenever the counter is created or grown (creation build and level-up). The vault rest control refills the counter from these when the player declares a Short/Long rest. Absent = the counter doesn't refresh on rest."New value: +"Per-rest recovery rows for a finite free-cast counter, stamped from the granting rule's freeCast.recovery whenever the counter is created or grown (creation build and level-up). The vault rest control refills the counter from these when the player declares the rest a row's `on` field names. Absent = the counter doesn't refresh on rest."
      • changedInput schema / properties / stress / items / properties / name / description
        Previous value: -"Track name — 'Physical Stress' / 'Mental Stress' in Fate Core, 'Stress' in Fate Accelerated."New value: +"Track name, as the ruleset's sheet template names its tracks."
      • changedInput schema / properties / trackables / items / properties / slotLevel / description
        Previous value: -"Spell-slot level of this pool (Pact Magic: one pool whose level rises with character level), stamped at build from the granting rule's uses[].slotLevel. The sheet shows it on the trackable row ('Level N'). Absent = an ordinary counter."New value: +"Spell-slot level of this pool, stamped at build from the granting rule's uses[].slotLevel. The sheet shows it on the trackable row ('Level N'). Absent = an ordinary counter."
    • Changedvault_update_companion_state2 fields changed
      • changedInput schema / properties / state / properties / exhaustion / description
        Previous value: -"5e24 Exhaustion level (0-6) tracked locally for the buddy."New value: +"Exhaustion level, within the schema's range, tracked locally for the buddy."
      • changedInput schema / properties / state / properties / hitDice / properties / pools / items / properties / dice / description
        Previous value: -"Die size of this pool, e.g. 'd10'. Must match a pool on the source character."New value: +"Die size of this pool. Must match a pool on the source character."
    • Changedvault_update_item74 fields changed
      • changedInput schema / properties / abilityScoreBump / properties / options / items / properties / lines / items / properties / eligible / description
        Previous value: -"Pool to choose from. Empty / absent = any of the six."New value: +"Pool to choose from. Empty / absent = any ability in the schema's abilities list."
      • changedInput schema / properties / abilityScoreBump / properties / options / items / properties / lines / items / properties / max / description
        Previous value: -"Ceiling no chosen score may exceed after the bump (ASI = 20)."New value: +"Ceiling no chosen score may exceed after the bump. The rule authoring guide's abilityScoreBump section shows the values."
      • changedInput schema / properties / abilityScoreBump / properties / options / items / properties / lines / items / properties / max / maximum
        Previous value: -9007199254740991New value: +30
      • changedInput schema / properties / abilityScoreSet / items / properties / value / maximum
        Previous value: -9007199254740991New value: +30
      • changedInput schema / properties / armorCategory / description
        Previous value: -"Armor category ('Light', 'Medium', 'Heavy', 'Shield')."New value: +"Armor category, as the ruleset's catalog names it (vault_search_items shows them)."
      • changedInput schema / properties / damageReduction / items / properties / requires / items / properties / armorCategories / description
        Previous value: -"For 'equipped' + slot:armor: armor category list (Light / Medium / Heavy). OR semantics — match any."New value: +"Armor categories to match, as the items' `armorCategory` values name them. OR semantics — match any."
      • changedInput schema / properties / damageReduction / items / properties / requires / items / properties / condition / description
        Previous value: -"For 'condition' predicates: the character-state condition to gate on (5e24 named conditions and ongoing-action states)."New value: +"For 'condition' predicates: the character-state condition to gate on (named conditions and ongoing-action states)."
      • changedInput schema / properties / damageReduction / items / properties / requires / items / properties / condition / enum
        Previous value: -[
        -  "blinded",
        -  "charmed",
        -  "dazed",
        -  "deafened",
        -  "exhaustion",
        -  "frightened",
        -  "grappled",
        -  "incapacitated",
        -  "invisible",
        -  "paralyzed",
        -  "petrified",
        -  "poisoned",
        -  "prone",
        -  "restrained",
        -  "stunned",
        -  "unconscious",
        -  "concentrating",
        -  "grappling",
        -  "dodging",
        -  "hiding",
        -  "raging"
        -]New value: +[
        +  "blinded",
        +  "charmed",
        +  "concentration",
        +  "deafened",
        +  "exhaustion",
        +  "frightened",
        +  "grappled",
        +  "incapacitated",
        +  "invisible",
        +  "paralyzed",
        +  "petrified",
        +  "poisoned",
        +  "prone",
        +  "restrained",
        +  "stunned",
        +  "unconscious",
        +  "dazed",
        +  "grappling",
        +  "dodging",
        +  "hiding",
        +  "raging"
        +]
      • changedInput schema / properties / damageReduction / items / properties / requires / items / properties / equipSlot / description
        Previous value: -"Body slot the matched weapon must occupy. mainHand / offHand. Resolved via getRequiredSlots so two-handed grips occupy both."New value: +"Body slot the matched weapon must occupy (one of the schema's enum)."
      • changedInput schema / properties / damageReduction / items / properties / requires / items / properties / slot / description
        Previous value: -"For 'equipped' predicates: the body category to match (armor / shield / weapon)."New value: +"The equipped body category to match (one of the schema's enum)."
      • changedInput schema / properties / damageReduction / items / properties / requires / items / properties / type / description
        Previous value: -"Predicate type. 'equipped' = character-scoped (gates on what's equipped). 'attackingWeapon' = attack-scoped (gates on the current action's source weapon). 'condition' = gates on a character-state condition."New value: +"Predicate type (one of the schema's enum): what the predicate gates on."
      • changedInput schema / properties / damageReduction / items / properties / requires / items / properties / weaponProperties / description
        Previous value: -"For 'equipped' + slot:weapon OR 'attackingWeapon': weapon-property list. AND semantics — match all."New value: +"Weapon properties to match. AND semantics — match all."
      • changedInput schema / properties / diceFloors / items / properties / requires / items / properties / armorCategories / description
        Previous value: -"For 'equipped' + slot:armor: armor category list (Light / Medium / Heavy). OR semantics — match any."New value: +"Armor categories to match, as the items' `armorCategory` values name them. OR semantics — match any."
      • changedInput schema / properties / diceFloors / items / properties / requires / items / properties / condition / description
        Previous value: -"For 'condition' predicates: the character-state condition to gate on (5e24 named conditions and ongoing-action states)."New value: +"For 'condition' predicates: the character-state condition to gate on (named conditions and ongoing-action states)."
      • changedInput schema / properties / diceFloors / items / properties / requires / items / properties / condition / enum
        Previous value: -[
        -  "blinded",
        -  "charmed",
        -  "dazed",
        -  "deafened",
        -  "exhaustion",
        -  "frightened",
        -  "grappled",
        -  "incapacitated",
        -  "invisible",
        -  "paralyzed",
        -  "petrified",
        -  "poisoned",
        -  "prone",
        -  "restrained",
        -  "stunned",
        -  "unconscious",
        -  "concentrating",
        -  "grappling",
        -  "dodging",
        -  "hiding",
        -  "raging"
        -]New value: +[
        +  "blinded",
        +  "charmed",
        +  "concentration",
        +  "deafened",
        +  "exhaustion",
        +  "frightened",
        +  "grappled",
        +  "incapacitated",
        +  "invisible",
        +  "paralyzed",
        +  "petrified",
        +  "poisoned",
        +  "prone",
        +  "restrained",
        +  "stunned",
        +  "unconscious",
        +  "dazed",
        +  "grappling",
        +  "dodging",
        +  "hiding",
        +  "raging"
        +]
      • changedInput schema / properties / diceFloors / items / properties / requires / items / properties / equipSlot / description
        Previous value: -"Body slot the matched weapon must occupy. mainHand / offHand. Resolved via getRequiredSlots so two-handed grips occupy both."New value: +"Body slot the matched weapon must occupy (one of the schema's enum)."
      • changedInput schema / properties / diceFloors / items / properties / requires / items / properties / slot / description
        Previous value: -"For 'equipped' predicates: the body category to match (armor / shield / weapon)."New value: +"The equipped body category to match (one of the schema's enum)."
      • changedInput schema / properties / diceFloors / items / properties / requires / items / properties / type / description
        Previous value: -"Predicate type. 'equipped' = character-scoped (gates on what's equipped). 'attackingWeapon' = attack-scoped (gates on the current action's source weapon). 'condition' = gates on a character-state condition."New value: +"Predicate type (one of the schema's enum): what the predicate gates on."
      • changedInput schema / properties / diceFloors / items / properties / requires / items / properties / weaponProperties / description
        Previous value: -"For 'equipped' + slot:weapon OR 'attackingWeapon': weapon-property list. AND semantics — match all."New value: +"Weapon properties to match. AND semantics — match all."
      • changedInput schema / properties / diceReplacements / items / properties / requires / items / properties / armorCategories / description
        Previous value: -"For 'equipped' + slot:armor: armor category list (Light / Medium / Heavy). OR semantics — match any."New value: +"Armor categories to match, as the items' `armorCategory` values name them. OR semantics — match any."
      • changedInput schema / properties / diceReplacements / items / properties / requires / items / properties / condition / description
        Previous value: -"For 'condition' predicates: the character-state condition to gate on (5e24 named conditions and ongoing-action states)."New value: +"For 'condition' predicates: the character-state condition to gate on (named conditions and ongoing-action states)."
      • changedInput schema / properties / diceReplacements / items / properties / requires / items / properties / condition / enum
        Previous value: -[
        -  "blinded",
        -  "charmed",
        -  "dazed",
        -  "deafened",
        -  "exhaustion",
        -  "frightened",
        -  "grappled",
        -  "incapacitated",
        -  "invisible",
        -  "paralyzed",
        -  "petrified",
        -  "poisoned",
        -  "prone",
        -  "restrained",
        -  "stunned",
        -  "unconscious",
        -  "concentrating",
        -  "grappling",
        -  "dodging",
        -  "hiding",
        -  "raging"
        -]New value: +[
        +  "blinded",
        +  "charmed",
        +  "concentration",
        +  "deafened",
        +  "exhaustion",
        +  "frightened",
        +  "grappled",
        +  "incapacitated",
        +  "invisible",
        +  "paralyzed",
        +  "petrified",
        +  "poisoned",
        +  "prone",
        +  "restrained",
        +  "stunned",
        +  "unconscious",
        +  "dazed",
        +  "grappling",
        +  "dodging",
        +  "hiding",
        +  "raging"
        +]
      • changedInput schema / properties / diceReplacements / items / properties / requires / items / properties / equipSlot / description
        Previous value: -"Body slot the matched weapon must occupy. mainHand / offHand. Resolved via getRequiredSlots so two-handed grips occupy both."New value: +"Body slot the matched weapon must occupy (one of the schema's enum)."
      • changedInput schema / properties / diceReplacements / items / properties / requires / items / properties / slot / description
        Previous value: -"For 'equipped' predicates: the body category to match (armor / shield / weapon)."New value: +"The equipped body category to match (one of the schema's enum)."
      • changedInput schema / properties / diceReplacements / items / properties / requires / items / properties / type / description
        Previous value: -"Predicate type. 'equipped' = character-scoped (gates on what's equipped). 'attackingWeapon' = attack-scoped (gates on the current action's source weapon). 'condition' = gates on a character-state condition."New value: +"Predicate type (one of the schema's enum): what the predicate gates on."
      • changedInput schema / properties / diceReplacements / items / properties / requires / items / properties / weaponProperties / description
        Previous value: -"For 'equipped' + slot:weapon OR 'attackingWeapon': weapon-property list. AND semantics — match all."New value: +"Weapon properties to match. AND semantics — match all."
      • changedInput schema / properties / equipSlots / description
        Previous value: -"Allowed equip slot ids (e.g. 'mainHand', 'offHand', 'body'). Vocabulary is ruleset-specific."New value: +"Allowed equip slot ids, from the ruleset's own slots (an existing item's equipSlots, via vault_get_item, shows them)."
      • changedInput schema / properties / forcedMovement / items / properties / requires / items / properties / armorCategories / description
        Previous value: -"For 'equipped' + slot:armor: armor category list (Light / Medium / Heavy). OR semantics — match any."New value: +"Armor categories to match, as the items' `armorCategory` values name them. OR semantics — match any."
      • changedInput schema / properties / forcedMovement / items / properties / requires / items / properties / condition / description
        Previous value: -"For 'condition' predicates: the character-state condition to gate on (5e24 named conditions and ongoing-action states)."New value: +"For 'condition' predicates: the character-state condition to gate on (named conditions and ongoing-action states)."
      • changedInput schema / properties / forcedMovement / items / properties / requires / items / properties / condition / enum
        Previous value: -[
        -  "blinded",
        -  "charmed",
        -  "dazed",
        -  "deafened",
        -  "exhaustion",
        -  "frightened",
        -  "grappled",
        -  "incapacitated",
        -  "invisible",
        -  "paralyzed",
        -  "petrified",
        -  "poisoned",
        -  "prone",
        -  "restrained",
        -  "stunned",
        -  "unconscious",
        -  "concentrating",
        -  "grappling",
        -  "dodging",
        -  "hiding",
        -  "raging"
        -]New value: +[
        +  "blinded",
        +  "charmed",
        +  "concentration",
        +  "deafened",
        +  "exhaustion",
        +  "frightened",
        +  "grappled",
        +  "incapacitated",
        +  "invisible",
        +  "paralyzed",
        +  "petrified",
        +  "poisoned",
        +  "prone",
        +  "restrained",
        +  "stunned",
        +  "unconscious",
        +  "dazed",
        +  "grappling",
        +  "dodging",
        +  "hiding",
        +  "raging"
        +]
      • changedInput schema / properties / forcedMovement / items / properties / requires / items / properties / equipSlot / description
        Previous value: -"Body slot the matched weapon must occupy. mainHand / offHand. Resolved via getRequiredSlots so two-handed grips occupy both."New value: +"Body slot the matched weapon must occupy (one of the schema's enum)."
      • changedInput schema / properties / forcedMovement / items / properties / requires / items / properties / slot / description
        Previous value: -"For 'equipped' predicates: the body category to match (armor / shield / weapon)."New value: +"The equipped body category to match (one of the schema's enum)."
      • changedInput schema / properties / forcedMovement / items / properties / requires / items / properties / type / description
        Previous value: -"Predicate type. 'equipped' = character-scoped (gates on what's equipped). 'attackingWeapon' = attack-scoped (gates on the current action's source weapon). 'condition' = gates on a character-state condition."New value: +"Predicate type (one of the schema's enum): what the predicate gates on."
      • changedInput schema / properties / forcedMovement / items / properties / requires / items / properties / weaponProperties / description
        Previous value: -"For 'equipped' + slot:weapon OR 'attackingWeapon': weapon-property list. AND semantics — match all."New value: +"Weapon properties to match. AND semantics — match all."
      • changedInput schema / properties / mastery / description
        Previous value: -"5e24 weapon mastery name (e.g. 'Topple', 'Vex', 'Slow')."New value: +"Weapon mastery name, for rulesets whose weapons carry one, as the ruleset's catalog names it."
      • changedInput schema / properties / maxDexModifier / description
        Previous value: -"Cap on DEX bonus from this armor (medium = 2; heavy = 0 typically)."New value: +"Cap on the DEX bonus this armor allows, from the item's source text."
      • changedInput schema / properties / prerequisites / items / properties / abilities / description
        Previous value: -"For abilityScore: ANY listed ability meeting `min` satisfies ('Str or Dex 13+')."New value: +"For abilityScore: ANY listed ability meeting `min` satisfies."
      • changedInput schema / properties / prerequisites / items / properties / proficiency / description
        Previous value: -"For proficiency: the proficiency name (e.g. 'Martial', 'Stealth')."New value: +"For proficiency: the proficiency name, as the ruleset names it."
      • changedInput schema / properties / prerequisites / items / properties / proficiencyType / enum
        Previous value: -[
        -  "skill",
        -  "tool",
        -  "weapon",
        -  "armor",
        -  "save",
        -  "language"
        -]New value: +[
        +  "skill",
        +  "tool",
        +  "save",
        +  "weapon",
        +  "armor",
        +  "language"
        +]
      • changedInput schema / properties / prerequisites / items / properties / type / description
        Previous value: -"Predicate kind: level / abilityScore / rule / spell / proficiency / spellcasting. (A class is required via a `rule` predicate pointing at the class rule.)"New value: +"Predicate kind. (A class is required via a `rule` predicate pointing at the class rule.)"
      • changedInput schema / properties / properties / items / properties / ammoType / description
        Previous value: -"Ammunition type for the Ammunition property (e.g. 'Arrow', 'Bolt')."New value: +"Ammunition type, for a property that uses ammunition."
      • changedInput schema / properties / properties / items / properties / damage / description
        Previous value: -"Per-property damage dice override (e.g. Versatile's two-hand dice)."New value: +"Per-property damage dice override, for a property that changes the weapon's damage."
      • changedInput schema / properties / properties / items / properties / name / description
        Previous value: -"Property identifier (e.g. 'Finesse', 'Versatile', 'Ammunition')."New value: +"Property identifier, as the ruleset's catalog names it (vault_search_items shows them)."
      • changedInput schema / properties / recurringDamage / items / properties / requires / items / properties / armorCategories / description
        Previous value: -"For 'equipped' + slot:armor: armor category list (Light / Medium / Heavy). OR semantics — match any."New value: +"Armor categories to match, as the items' `armorCategory` values name them. OR semantics — match any."
      • changedInput schema / properties / recurringDamage / items / properties / requires / items / properties / condition / description
        Previous value: -"For 'condition' predicates: the character-state condition to gate on (5e24 named conditions and ongoing-action states)."New value: +"For 'condition' predicates: the character-state condition to gate on (named conditions and ongoing-action states)."
      • changedInput schema / properties / recurringDamage / items / properties / requires / items / properties / condition / enum
        Previous value: -[
        -  "blinded",
        -  "charmed",
        -  "dazed",
        -  "deafened",
        -  "exhaustion",
        -  "frightened",
        -  "grappled",
        -  "incapacitated",
        -  "invisible",
        -  "paralyzed",
        -  "petrified",
        -  "poisoned",
        -  "prone",
        -  "restrained",
        -  "stunned",
        -  "unconscious",
        -  "concentrating",
        -  "grappling",
        -  "dodging",
        -  "hiding",
        -  "raging"
        -]New value: +[
        +  "blinded",
        +  "charmed",
        +  "concentration",
        +  "deafened",
        +  "exhaustion",
        +  "frightened",
        +  "grappled",
        +  "incapacitated",
        +  "invisible",
        +  "paralyzed",
        +  "petrified",
        +  "poisoned",
        +  "prone",
        +  "restrained",
        +  "stunned",
        +  "unconscious",
        +  "dazed",
        +  "grappling",
        +  "dodging",
        +  "hiding",
        +  "raging"
        +]
      • changedInput schema / properties / recurringDamage / items / properties / requires / items / properties / equipSlot / description
        Previous value: -"Body slot the matched weapon must occupy. mainHand / offHand. Resolved via getRequiredSlots so two-handed grips occupy both."New value: +"Body slot the matched weapon must occupy (one of the schema's enum)."
      • changedInput schema / properties / recurringDamage / items / properties / requires / items / properties / slot / description
        Previous value: -"For 'equipped' predicates: the body category to match (armor / shield / weapon)."New value: +"The equipped body category to match (one of the schema's enum)."
      • changedInput schema / properties / recurringDamage / items / properties / requires / items / properties / type / description
        Previous value: -"Predicate type. 'equipped' = character-scoped (gates on what's equipped). 'attackingWeapon' = attack-scoped (gates on the current action's source weapon). 'condition' = gates on a character-state condition."New value: +"Predicate type (one of the schema's enum): what the predicate gates on."
      • changedInput schema / properties / recurringDamage / items / properties / requires / items / properties / weaponProperties / description
        Previous value: -"For 'equipped' + slot:weapon OR 'attackingWeapon': weapon-property list. AND semantics — match all."New value: +"Weapon properties to match. AND semantics — match all."
      • changedInput schema / properties / resistances / items / properties / range / description
        Previous value: -"Aura radius in feet for ally/any-targeted resistances (Warding Aura's 10 ft.). Absent = self-only."New value: +"Aura radius in feet for ally/any-targeted resistances. Absent = self-only."
      • changedInput schema / properties / rollMods / items / properties / requires / items / properties / armorCategories / description
        Previous value: -"For 'equipped' + slot:armor: armor category list (Light / Medium / Heavy). OR semantics — match any."New value: +"Armor categories to match, as the items' `armorCategory` values name them. OR semantics — match any."
      • changedInput schema / properties / rollMods / items / properties / requires / items / properties / condition / description
        Previous value: -"For 'condition' predicates: the character-state condition to gate on (5e24 named conditions and ongoing-action states)."New value: +"For 'condition' predicates: the character-state condition to gate on (named conditions and ongoing-action states)."
      • changedInput schema / properties / rollMods / items / properties / requires / items / properties / condition / enum
        Previous value: -[
        -  "blinded",
        -  "charmed",
        -  "dazed",
        -  "deafened",
        -  "exhaustion",
        -  "frightened",
        -  "grappled",
        -  "incapacitated",
        -  "invisible",
        -  "paralyzed",
        -  "petrified",
        -  "poisoned",
        -  "prone",
        -  "restrained",
        -  "stunned",
        -  "unconscious",
        -  "concentrating",
        -  "grappling",
        -  "dodging",
        -  "hiding",
        -  "raging"
        -]New value: +[
        +  "blinded",
        +  "charmed",
        +  "concentration",
        +  "deafened",
        +  "exhaustion",
        +  "frightened",
        +  "grappled",
        +  "incapacitated",
        +  "invisible",
        +  "paralyzed",
        +  "petrified",
        +  "poisoned",
        +  "prone",
        +  "restrained",
        +  "stunned",
        +  "unconscious",
        +  "dazed",
        +  "grappling",
        +  "dodging",
        +  "hiding",
        +  "raging"
        +]
      • changedInput schema / properties / rollMods / items / properties / requires / items / properties / equipSlot / description
        Previous value: -"Body slot the matched weapon must occupy. mainHand / offHand. Resolved via getRequiredSlots so two-handed grips occupy both."New value: +"Body slot the matched weapon must occupy (one of the schema's enum)."
      • changedInput schema / properties / rollMods / items / properties / requires / items / properties / slot / description
        Previous value: -"For 'equipped' predicates: the body category to match (armor / shield / weapon)."New value: +"The equipped body category to match (one of the schema's enum)."
      • changedInput schema / properties / rollMods / items / properties / requires / items / properties / type / description
        Previous value: -"Predicate type. 'equipped' = character-scoped (gates on what's equipped). 'attackingWeapon' = attack-scoped (gates on the current action's source weapon). 'condition' = gates on a character-state condition."New value: +"Predicate type (one of the schema's enum): what the predicate gates on."
      • changedInput schema / properties / rollMods / items / properties / requires / items / properties / weaponProperties / description
        Previous value: -"For 'equipped' + slot:weapon OR 'attackingWeapon': weapon-property list. AND semantics — match all."New value: +"Weapon properties to match. AND semantics — match all."
      • changedInput schema / properties / ruleset / description
        Previous value: -"Ruleset code (e.g. '5th Edition', '5e24', 'PFRPG', 'Savage Worlds')."New value: +"Ruleset code, from list_rulesets."
      • changedInput schema / properties / statBonuses / items / properties / durationCount / description
        Previous value: -"Numeric count paired with durationUnit (e.g. count: 3, unit: 'round')."New value: +"Numeric count paired with durationUnit."
      • changedInput schema / properties / statBonuses / items / properties / range / description
        Previous value: -"Aura radius in feet for ally/any-audience bonuses (Aura of Protection's 10 ft.). Absent = no range filter."New value: +"Aura radius in feet for ally/any-audience bonuses. Absent = no range filter."
      • changedInput schema / properties / statBonuses / items / properties / requires / items / properties / armorCategories / description
        Previous value: -"For 'equipped' + slot:armor: armor category list (Light / Medium / Heavy). OR semantics — match any."New value: +"Armor categories to match, as the items' `armorCategory` values name them. OR semantics — match any."
      • changedInput schema / properties / statBonuses / items / properties / requires / items / properties / condition / description
        Previous value: -"For 'condition' predicates: the character-state condition to gate on (5e24 named conditions and ongoing-action states)."New value: +"For 'condition' predicates: the character-state condition to gate on (named conditions and ongoing-action states)."
      • changedInput schema / properties / statBonuses / items / properties / requires / items / properties / condition / enum
        Previous value: -[
        -  "blinded",
        -  "charmed",
        -  "dazed",
        -  "deafened",
        -  "exhaustion",
        -  "frightened",
        -  "grappled",
        -  "incapacitated",
        -  "invisible",
        -  "paralyzed",
        -  "petrified",
        -  "poisoned",
        -  "prone",
        -  "restrained",
        -  "stunned",
        -  "unconscious",
        -  "concentrating",
        -  "grappling",
        -  "dodging",
        -  "hiding",
        -  "raging"
        -]New value: +[
        +  "blinded",
        +  "charmed",
        +  "concentration",
        +  "deafened",
        +  "exhaustion",
        +  "frightened",
        +  "grappled",
        +  "incapacitated",
        +  "invisible",
        +  "paralyzed",
        +  "petrified",
        +  "poisoned",
        +  "prone",
        +  "restrained",
        +  "stunned",
        +  "unconscious",
        +  "dazed",
        +  "grappling",
        +  "dodging",
        +  "hiding",
        +  "raging"
        +]
      • changedInput schema / properties / statBonuses / items / properties / requires / items / properties / equipSlot / description
        Previous value: -"Body slot the matched weapon must occupy. mainHand / offHand. Resolved via getRequiredSlots so two-handed grips occupy both."New value: +"Body slot the matched weapon must occupy (one of the schema's enum)."
      • changedInput schema / properties / statBonuses / items / properties / requires / items / properties / slot / description
        Previous value: -"For 'equipped' predicates: the body category to match (armor / shield / weapon)."New value: +"The equipped body category to match (one of the schema's enum)."
      • changedInput schema / properties / statBonuses / items / properties / requires / items / properties / type / description
        Previous value: -"Predicate type. 'equipped' = character-scoped (gates on what's equipped). 'attackingWeapon' = attack-scoped (gates on the current action's source weapon). 'condition' = gates on a character-state condition."New value: +"Predicate type (one of the schema's enum): what the predicate gates on."
      • changedInput schema / properties / statBonuses / items / properties / requires / items / properties / weaponProperties / description
        Previous value: -"For 'equipped' + slot:weapon OR 'attackingWeapon': weapon-property list. AND semantics — match all."New value: +"Weapon properties to match. AND semantics — match all."
      • changedInput schema / properties / statBonuses / items / properties / target / description
        Previous value: -"Stat the bonus contributes to (e.g. 'skills.Acrobatics.misc', 'attributes.strength.misc')."New value: +"Stat the bonus contributes to (e.g. 'skills.<skill>.misc', 'attributes.<ability>.misc')."
      • changedInput schema / properties / statBonuses / items / properties / trigger / description
        Previous value: -"Action-economy / cost shape of the bonus. passive / toggled / reaction / perRoll / resource / targetBound."New value: +"Action-economy / cost shape of the bonus."
      • changedInput schema / properties / statBonuses / items / properties / triggerEvent / description
        Previous value: -"Game-time event that fires the bonus (onHit / onDamage / startOfYourTurn / etc.). Absent = not event-driven (passive walker contributes whenever `requires` holds)."New value: +"Game-time event that fires the bonus (one of the schema's trigger events). Absent = not event-driven (passive walker contributes whenever `requires` holds)."
      • changedInput schema / properties / statBonuses / items / properties / valueType / enum
        Previous value: -[
        -  "fixed",
        -  "attribute",
        -  "proficiency",
        -  "level",
        -  "halfLevel",
        -  "dice",
        -  "byLevel",
        -  "attackAttribute"
        -]New value: +[
        +  "fixed",
        +  "attribute",
        +  "attackAttribute",
        +  "proficiency",
        +  "level",
        +  "halfLevel",
        +  "dice",
        +  "byLevel"
        +]
      • changedInput schema / properties / type / description
        Previous value: -"Item type. Free-form per ruleset (Weapon, Armor, Tool, Adventuring Gear, Wondrous Item, etc.). Required at create."New value: +"Item type. Free-form per ruleset; match the types the ruleset's catalog uses (vault_search_items shows them). Required at create."
      • changedInput schema / properties / weaponType / description
        Previous value: -"Weapon category ('Simple Melee', 'Martial Ranged', etc.)."New value: +"Weapon category, as the ruleset's catalog names it (vault_search_items shows them)."
    • Changedvault_update_rule73 fields changed
      • changedInput schema / properties / abilityScoreBump / properties / options / items / properties / lines / items / properties / eligible / description
        Previous value: -"Pool to choose from. Empty / absent = any of the six."New value: +"Pool to choose from. Empty / absent = any ability in the schema's abilities list."
      • changedInput schema / properties / abilityScoreBump / properties / options / items / properties / lines / items / properties / max / description
        Previous value: -"Ceiling no chosen score may exceed after the bump (ASI = 20)."New value: +"Ceiling no chosen score may exceed after the bump. The rule authoring guide's abilityScoreBump section shows the values."
      • changedInput schema / properties / abilityScoreBump / properties / options / items / properties / lines / items / properties / max / maximum
        Previous value: -9007199254740991New value: +30
      • changedInput schema / properties / abilityScoreSet / items / properties / value / maximum
        Previous value: -9007199254740991New value: +30
      • changedInput schema / properties / actionEconomy / description
        Previous value: -"What invoking the ability costs on a turn: 'Action', 'Bonus Action', or 'Reaction'. Distinct from the mechanics actionType (a kind-of-action label). Absent = the ability takes the action."New value: +"What invoking the ability costs on a turn. The rule authoring guide (vault_get_authoring_guide, entityType 'rule') gives the absent default. Distinct from the mechanics actionType (a kind-of-action label)."
      • addedInput schema / properties / actionEconomy / enum
        Added value: +[
        +  "Action",
        +  "Bonus Action",
        +  "Reaction"
        +]
      • changedInput schema / properties / actions / description
        Previous value: -"PF Playtest action-economy marker (F/1/2/3/R)."New value: +"Action-cost marker, for rulesets whose rules carry one; the value is the source text."
      • changedInput schema / properties / casterProgression / description
        Previous value: -"How this class contributes to the combined multiclass spell-slot pool: full casters count every level, half/third round up, 'pact' (Pact Magic) keeps its own pool and never joins. Authorable on a base class or a subclass (a third-caster subclass carries it). Absent = non-caster."New value: +"How this class contributes to the combined multiclass spell-slot pool; the engine applies each progression's rule. Authorable on a base class or a subclass (a subclass that grants the casting carries it). Absent = non-caster."
      • changedInput schema / properties / castingAbility / description
        Previous value: -"The ability this rule's spellcasting keys off ('Intelligence is your spellcasting ability for your Wizard spells'). Author it on a class's Spellcasting ability rule; vault's creation and level-up wizards write it to the character-wide Spellcasting Ability (first-wins, never overwriting), and a multiclass whose ability differs stamps its granted spells per-entry. Distinct from a spell block's castingAbility, which overrides per grant. Absent = the rule says nothing about the character's casting ability."New value: +"The ability this rule's spellcasting keys off. Author it on a class's Spellcasting ability rule; vault's creation and level-up wizards write it to the character-wide Spellcasting Ability (first-wins, never overwriting), and a multiclass whose ability differs stamps its granted spells per-entry. Distinct from a spell block's castingAbility, which overrides per grant. Absent = the rule says nothing about the character's casting ability."
      • changedInput schema / properties / damageReduction / items / properties / requires / items / properties / armorCategories / description
        Previous value: -"For 'equipped' + slot:armor: armor category list (Light / Medium / Heavy). OR semantics — match any."New value: +"Armor categories to match, as the items' `armorCategory` values name them. OR semantics — match any."
      • changedInput schema / properties / damageReduction / items / properties / requires / items / properties / condition / description
        Previous value: -"For 'condition' predicates: the character-state condition to gate on (5e24 named conditions and ongoing-action states)."New value: +"For 'condition' predicates: the character-state condition to gate on (named conditions and ongoing-action states)."
      • changedInput schema / properties / damageReduction / items / properties / requires / items / properties / condition / enum
        Previous value: -[
        -  "blinded",
        -  "charmed",
        -  "dazed",
        -  "deafened",
        -  "exhaustion",
        -  "frightened",
        -  "grappled",
        -  "incapacitated",
        -  "invisible",
        -  "paralyzed",
        -  "petrified",
        -  "poisoned",
        -  "prone",
        -  "restrained",
        -  "stunned",
        -  "unconscious",
        -  "concentrating",
        -  "grappling",
        -  "dodging",
        -  "hiding",
        -  "raging"
        -]New value: +[
        +  "blinded",
        +  "charmed",
        +  "concentration",
        +  "deafened",
        +  "exhaustion",
        +  "frightened",
        +  "grappled",
        +  "incapacitated",
        +  "invisible",
        +  "paralyzed",
        +  "petrified",
        +  "poisoned",
        +  "prone",
        +  "restrained",
        +  "stunned",
        +  "unconscious",
        +  "dazed",
        +  "grappling",
        +  "dodging",
        +  "hiding",
        +  "raging"
        +]
      • changedInput schema / properties / damageReduction / items / properties / requires / items / properties / equipSlot / description
        Previous value: -"Body slot the matched weapon must occupy. mainHand / offHand. Resolved via getRequiredSlots so two-handed grips occupy both."New value: +"Body slot the matched weapon must occupy (one of the schema's enum)."
      • changedInput schema / properties / damageReduction / items / properties / requires / items / properties / slot / description
        Previous value: -"For 'equipped' predicates: the body category to match (armor / shield / weapon)."New value: +"The equipped body category to match (one of the schema's enum)."
      • changedInput schema / properties / damageReduction / items / properties / requires / items / properties / type / description
        Previous value: -"Predicate type. 'equipped' = character-scoped (gates on what's equipped). 'attackingWeapon' = attack-scoped (gates on the current action's source weapon). 'condition' = gates on a character-state condition."New value: +"Predicate type (one of the schema's enum): what the predicate gates on."
      • changedInput schema / properties / damageReduction / items / properties / requires / items / properties / weaponProperties / description
        Previous value: -"For 'equipped' + slot:weapon OR 'attackingWeapon': weapon-property list. AND semantics — match all."New value: +"Weapon properties to match. AND semantics — match all."
      • changedInput schema / properties / diceFloors / items / properties / requires / items / properties / armorCategories / description
        Previous value: -"For 'equipped' + slot:armor: armor category list (Light / Medium / Heavy). OR semantics — match any."New value: +"Armor categories to match, as the items' `armorCategory` values name them. OR semantics — match any."
      • changedInput schema / properties / diceFloors / items / properties / requires / items / properties / condition / description
        Previous value: -"For 'condition' predicates: the character-state condition to gate on (5e24 named conditions and ongoing-action states)."New value: +"For 'condition' predicates: the character-state condition to gate on (named conditions and ongoing-action states)."
      • changedInput schema / properties / diceFloors / items / properties / requires / items / properties / condition / enum
        Previous value: -[
        -  "blinded",
        -  "charmed",
        -  "dazed",
        -  "deafened",
        -  "exhaustion",
        -  "frightened",
        -  "grappled",
        -  "incapacitated",
        -  "invisible",
        -  "paralyzed",
        -  "petrified",
        -  "poisoned",
        -  "prone",
        -  "restrained",
        -  "stunned",
        -  "unconscious",
        -  "concentrating",
        -  "grappling",
        -  "dodging",
        -  "hiding",
        -  "raging"
        -]New value: +[
        +  "blinded",
        +  "charmed",
        +  "concentration",
        +  "deafened",
        +  "exhaustion",
        +  "frightened",
        +  "grappled",
        +  "incapacitated",
        +  "invisible",
        +  "paralyzed",
        +  "petrified",
        +  "poisoned",
        +  "prone",
        +  "restrained",
        +  "stunned",
        +  "unconscious",
        +  "dazed",
        +  "grappling",
        +  "dodging",
        +  "hiding",
        +  "raging"
        +]
      • changedInput schema / properties / diceFloors / items / properties / requires / items / properties / equipSlot / description
        Previous value: -"Body slot the matched weapon must occupy. mainHand / offHand. Resolved via getRequiredSlots so two-handed grips occupy both."New value: +"Body slot the matched weapon must occupy (one of the schema's enum)."
      • changedInput schema / properties / diceFloors / items / properties / requires / items / properties / slot / description
        Previous value: -"For 'equipped' predicates: the body category to match (armor / shield / weapon)."New value: +"The equipped body category to match (one of the schema's enum)."
      • changedInput schema / properties / diceFloors / items / properties / requires / items / properties / type / description
        Previous value: -"Predicate type. 'equipped' = character-scoped (gates on what's equipped). 'attackingWeapon' = attack-scoped (gates on the current action's source weapon). 'condition' = gates on a character-state condition."New value: +"Predicate type (one of the schema's enum): what the predicate gates on."
      • changedInput schema / properties / diceFloors / items / properties / requires / items / properties / weaponProperties / description
        Previous value: -"For 'equipped' + slot:weapon OR 'attackingWeapon': weapon-property list. AND semantics — match all."New value: +"Weapon properties to match. AND semantics — match all."
      • changedInput schema / properties / diceReplacements / items / properties / requires / items / properties / armorCategories / description
        Previous value: -"For 'equipped' + slot:armor: armor category list (Light / Medium / Heavy). OR semantics — match any."New value: +"Armor categories to match, as the items' `armorCategory` values name them. OR semantics — match any."
      • changedInput schema / properties / diceReplacements / items / properties / requires / items / properties / condition / description
        Previous value: -"For 'condition' predicates: the character-state condition to gate on (5e24 named conditions and ongoing-action states)."New value: +"For 'condition' predicates: the character-state condition to gate on (named conditions and ongoing-action states)."
      • changedInput schema / properties / diceReplacements / items / properties / requires / items / properties / condition / enum
        Previous value: -[
        -  "blinded",
        -  "charmed",
        -  "dazed",
        -  "deafened",
        -  "exhaustion",
        -  "frightened",
        -  "grappled",
        -  "incapacitated",
        -  "invisible",
        -  "paralyzed",
        -  "petrified",
        -  "poisoned",
        -  "prone",
        -  "restrained",
        -  "stunned",
        -  "unconscious",
        -  "concentrating",
        -  "grappling",
        -  "dodging",
        -  "hiding",
        -  "raging"
        -]New value: +[
        +  "blinded",
        +  "charmed",
        +  "concentration",
        +  "deafened",
        +  "exhaustion",
        +  "frightened",
        +  "grappled",
        +  "incapacitated",
        +  "invisible",
        +  "paralyzed",
        +  "petrified",
        +  "poisoned",
        +  "prone",
        +  "restrained",
        +  "stunned",
        +  "unconscious",
        +  "dazed",
        +  "grappling",
        +  "dodging",
        +  "hiding",
        +  "raging"
        +]
      • changedInput schema / properties / diceReplacements / items / properties / requires / items / properties / equipSlot / description
        Previous value: -"Body slot the matched weapon must occupy. mainHand / offHand. Resolved via getRequiredSlots so two-handed grips occupy both."New value: +"Body slot the matched weapon must occupy (one of the schema's enum)."
      • changedInput schema / properties / diceReplacements / items / properties / requires / items / properties / slot / description
        Previous value: -"For 'equipped' predicates: the body category to match (armor / shield / weapon)."New value: +"The equipped body category to match (one of the schema's enum)."
      • changedInput schema / properties / diceReplacements / items / properties / requires / items / properties / type / description
        Previous value: -"Predicate type. 'equipped' = character-scoped (gates on what's equipped). 'attackingWeapon' = attack-scoped (gates on the current action's source weapon). 'condition' = gates on a character-state condition."New value: +"Predicate type (one of the schema's enum): what the predicate gates on."
      • changedInput schema / properties / diceReplacements / items / properties / requires / items / properties / weaponProperties / description
        Previous value: -"For 'equipped' + slot:weapon OR 'attackingWeapon': weapon-property list. AND semantics — match all."New value: +"Weapon properties to match. AND semantics — match all."
      • changedInput schema / properties / forcedMovement / items / properties / requires / items / properties / armorCategories / description
        Previous value: -"For 'equipped' + slot:armor: armor category list (Light / Medium / Heavy). OR semantics — match any."New value: +"Armor categories to match, as the items' `armorCategory` values name them. OR semantics — match any."
      • changedInput schema / properties / forcedMovement / items / properties / requires / items / properties / condition / description
        Previous value: -"For 'condition' predicates: the character-state condition to gate on (5e24 named conditions and ongoing-action states)."New value: +"For 'condition' predicates: the character-state condition to gate on (named conditions and ongoing-action states)."
      • changedInput schema / properties / forcedMovement / items / properties / requires / items / properties / condition / enum
        Previous value: -[
        -  "blinded",
        -  "charmed",
        -  "dazed",
        -  "deafened",
        -  "exhaustion",
        -  "frightened",
        -  "grappled",
        -  "incapacitated",
        -  "invisible",
        -  "paralyzed",
        -  "petrified",
        -  "poisoned",
        -  "prone",
        -  "restrained",
        -  "stunned",
        -  "unconscious",
        -  "concentrating",
        -  "grappling",
        -  "dodging",
        -  "hiding",
        -  "raging"
        -]New value: +[
        +  "blinded",
        +  "charmed",
        +  "concentration",
        +  "deafened",
        +  "exhaustion",
        +  "frightened",
        +  "grappled",
        +  "incapacitated",
        +  "invisible",
        +  "paralyzed",
        +  "petrified",
        +  "poisoned",
        +  "prone",
        +  "restrained",
        +  "stunned",
        +  "unconscious",
        +  "dazed",
        +  "grappling",
        +  "dodging",
        +  "hiding",
        +  "raging"
        +]
      • changedInput schema / properties / forcedMovement / items / properties / requires / items / properties / equipSlot / description
        Previous value: -"Body slot the matched weapon must occupy. mainHand / offHand. Resolved via getRequiredSlots so two-handed grips occupy both."New value: +"Body slot the matched weapon must occupy (one of the schema's enum)."
      • changedInput schema / properties / forcedMovement / items / properties / requires / items / properties / slot / description
        Previous value: -"For 'equipped' predicates: the body category to match (armor / shield / weapon)."New value: +"The equipped body category to match (one of the schema's enum)."
      • changedInput schema / properties / forcedMovement / items / properties / requires / items / properties / type / description
        Previous value: -"Predicate type. 'equipped' = character-scoped (gates on what's equipped). 'attackingWeapon' = attack-scoped (gates on the current action's source weapon). 'condition' = gates on a character-state condition."New value: +"Predicate type (one of the schema's enum): what the predicate gates on."
      • changedInput schema / properties / forcedMovement / items / properties / requires / items / properties / weaponProperties / description
        Previous value: -"For 'equipped' + slot:weapon OR 'attackingWeapon': weapon-property list. AND semantics — match all."New value: +"Weapon properties to match. AND semantics — match all."
      • changedInput schema / properties / prerequisites / items / properties / abilities / description
        Previous value: -"For abilityScore: ANY listed ability meeting `min` satisfies ('Str or Dex 13+')."New value: +"For abilityScore: ANY listed ability meeting `min` satisfies."
      • changedInput schema / properties / prerequisites / items / properties / proficiency / description
        Previous value: -"For proficiency: the proficiency name (e.g. 'Martial', 'Stealth')."New value: +"For proficiency: the proficiency name, as the ruleset names it."
      • changedInput schema / properties / prerequisites / items / properties / proficiencyType / enum
        Previous value: -[
        -  "skill",
        -  "tool",
        -  "weapon",
        -  "armor",
        -  "save",
        -  "language"
        -]New value: +[
        +  "skill",
        +  "tool",
        +  "save",
        +  "weapon",
        +  "armor",
        +  "language"
        +]
      • changedInput schema / properties / prerequisites / items / properties / type / description
        Previous value: -"Predicate kind: level / abilityScore / rule / spell / proficiency / spellcasting. (A class is required via a `rule` predicate pointing at the class rule.)"New value: +"Predicate kind. (A class is required via a `rule` predicate pointing at the class rule.)"
      • changedInput schema / properties / range / description
        Previous value: -"How far the ability reaches when invoked — self, touch, or ranged with a distance ('feet' default, 'miles' for long reaches). Absent = runtime defaults (self-heals on the user, targeted abilities at touch)."New value: +"How far the ability reaches when invoked: `kind`, plus `distance` and its `unit` for a kind that takes a distance. Absent: the rule authoring guide (vault_get_authoring_guide, entityType 'rule') gives the default."
      • changedInput schema / properties / recurringDamage / items / properties / requires / items / properties / armorCategories / description
        Previous value: -"For 'equipped' + slot:armor: armor category list (Light / Medium / Heavy). OR semantics — match any."New value: +"Armor categories to match, as the items' `armorCategory` values name them. OR semantics — match any."
      • changedInput schema / properties / recurringDamage / items / properties / requires / items / properties / condition / description
        Previous value: -"For 'condition' predicates: the character-state condition to gate on (5e24 named conditions and ongoing-action states)."New value: +"For 'condition' predicates: the character-state condition to gate on (named conditions and ongoing-action states)."
      • changedInput schema / properties / recurringDamage / items / properties / requires / items / properties / condition / enum
        Previous value: -[
        -  "blinded",
        -  "charmed",
        -  "dazed",
        -  "deafened",
        -  "exhaustion",
        -  "frightened",
        -  "grappled",
        -  "incapacitated",
        -  "invisible",
        -  "paralyzed",
        -  "petrified",
        -  "poisoned",
        -  "prone",
        -  "restrained",
        -  "stunned",
        -  "unconscious",
        -  "concentrating",
        -  "grappling",
        -  "dodging",
        -  "hiding",
        -  "raging"
        -]New value: +[
        +  "blinded",
        +  "charmed",
        +  "concentration",
        +  "deafened",
        +  "exhaustion",
        +  "frightened",
        +  "grappled",
        +  "incapacitated",
        +  "invisible",
        +  "paralyzed",
        +  "petrified",
        +  "poisoned",
        +  "prone",
        +  "restrained",
        +  "stunned",
        +  "unconscious",
        +  "dazed",
        +  "grappling",
        +  "dodging",
        +  "hiding",
        +  "raging"
        +]
      • changedInput schema / properties / recurringDamage / items / properties / requires / items / properties / equipSlot / description
        Previous value: -"Body slot the matched weapon must occupy. mainHand / offHand. Resolved via getRequiredSlots so two-handed grips occupy both."New value: +"Body slot the matched weapon must occupy (one of the schema's enum)."
      • changedInput schema / properties / recurringDamage / items / properties / requires / items / properties / slot / description
        Previous value: -"For 'equipped' predicates: the body category to match (armor / shield / weapon)."New value: +"The equipped body category to match (one of the schema's enum)."
      • changedInput schema / properties / recurringDamage / items / properties / requires / items / properties / type / description
        Previous value: -"Predicate type. 'equipped' = character-scoped (gates on what's equipped). 'attackingWeapon' = attack-scoped (gates on the current action's source weapon). 'condition' = gates on a character-state condition."New value: +"Predicate type (one of the schema's enum): what the predicate gates on."
      • changedInput schema / properties / recurringDamage / items / properties / requires / items / properties / weaponProperties / description
        Previous value: -"For 'equipped' + slot:weapon OR 'attackingWeapon': weapon-property list. AND semantics — match all."New value: +"Weapon properties to match. AND semantics — match all."
      • changedInput schema / properties / repeatable / description
        Previous value: -"A rule that may be taken/granted more than once, each time as a distinct instance with its own sub-choices — a repeatable Feat (Skilled, Resilient), or a class's Ability Score Improvement ability, which its class grants at several levels."New value: +"A rule that may be taken/granted more than once, each time as a distinct instance with its own sub-choices — a repeatable feat, or a class ability its class grants at several levels."
      • changedInput schema / properties / resistances / items / properties / range / description
        Previous value: -"Aura radius in feet for ally/any-targeted resistances (Warding Aura's 10 ft.). Absent = self-only."New value: +"Aura radius in feet for ally/any-targeted resistances. Absent = self-only."
      • changedInput schema / properties / rollMods / items / properties / requires / items / properties / armorCategories / description
        Previous value: -"For 'equipped' + slot:armor: armor category list (Light / Medium / Heavy). OR semantics — match any."New value: +"Armor categories to match, as the items' `armorCategory` values name them. OR semantics — match any."
      • changedInput schema / properties / rollMods / items / properties / requires / items / properties / condition / description
        Previous value: -"For 'condition' predicates: the character-state condition to gate on (5e24 named conditions and ongoing-action states)."New value: +"For 'condition' predicates: the character-state condition to gate on (named conditions and ongoing-action states)."
      • changedInput schema / properties / rollMods / items / properties / requires / items / properties / condition / enum
        Previous value: -[
        -  "blinded",
        -  "charmed",
        -  "dazed",
        -  "deafened",
        -  "exhaustion",
        -  "frightened",
        -  "grappled",
        -  "incapacitated",
        -  "invisible",
        -  "paralyzed",
        -  "petrified",
        -  "poisoned",
        -  "prone",
        -  "restrained",
        -  "stunned",
        -  "unconscious",
        -  "concentrating",
        -  "grappling",
        -  "dodging",
        -  "hiding",
        -  "raging"
        -]New value: +[
        +  "blinded",
        +  "charmed",
        +  "concentration",
        +  "deafened",
        +  "exhaustion",
        +  "frightened",
        +  "grappled",
        +  "incapacitated",
        +  "invisible",
        +  "paralyzed",
        +  "petrified",
        +  "poisoned",
        +  "prone",
        +  "restrained",
        +  "stunned",
        +  "unconscious",
        +  "dazed",
        +  "grappling",
        +  "dodging",
        +  "hiding",
        +  "raging"
        +]
      • changedInput schema / properties / rollMods / items / properties / requires / items / properties / equipSlot / description
        Previous value: -"Body slot the matched weapon must occupy. mainHand / offHand. Resolved via getRequiredSlots so two-handed grips occupy both."New value: +"Body slot the matched weapon must occupy (one of the schema's enum)."
      • changedInput schema / properties / rollMods / items / properties / requires / items / properties / slot / description
        Previous value: -"For 'equipped' predicates: the body category to match (armor / shield / weapon)."New value: +"The equipped body category to match (one of the schema's enum)."
      • changedInput schema / properties / rollMods / items / properties / requires / items / properties / type / description
        Previous value: -"Predicate type. 'equipped' = character-scoped (gates on what's equipped). 'attackingWeapon' = attack-scoped (gates on the current action's source weapon). 'condition' = gates on a character-state condition."New value: +"Predicate type (one of the schema's enum): what the predicate gates on."
      • changedInput schema / properties / rollMods / items / properties / requires / items / properties / weaponProperties / description
        Previous value: -"For 'equipped' + slot:weapon OR 'attackingWeapon': weapon-property list. AND semantics — match all."New value: +"Weapon properties to match. AND semantics — match all."
      • changedInput schema / properties / ruleset / description
        Previous value: -"Ruleset code (e.g. '5th Edition', '5e24', 'PFRPG', 'Savage Worlds', 'Universal')."New value: +"Ruleset code, from list_rulesets."
      • changedInput schema / properties / statBonuses / items / properties / durationCount / description
        Previous value: -"Numeric count paired with durationUnit (e.g. count: 3, unit: 'round')."New value: +"Numeric count paired with durationUnit."
      • changedInput schema / properties / statBonuses / items / properties / range / description
        Previous value: -"Aura radius in feet for ally/any-audience bonuses (Aura of Protection's 10 ft.). Absent = no range filter."New value: +"Aura radius in feet for ally/any-audience bonuses. Absent = no range filter."
      • changedInput schema / properties / statBonuses / items / properties / requires / items / properties / armorCategories / description
        Previous value: -"For 'equipped' + slot:armor: armor category list (Light / Medium / Heavy). OR semantics — match any."New value: +"Armor categories to match, as the items' `armorCategory` values name them. OR semantics — match any."
      • changedInput schema / properties / statBonuses / items / properties / requires / items / properties / condition / description
        Previous value: -"For 'condition' predicates: the character-state condition to gate on (5e24 named conditions and ongoing-action states)."New value: +"For 'condition' predicates: the character-state condition to gate on (named conditions and ongoing-action states)."
      • changedInput schema / properties / statBonuses / items / properties / requires / items / properties / condition / enum
        Previous value: -[
        -  "blinded",
        -  "charmed",
        -  "dazed",
        -  "deafened",
        -  "exhaustion",
        -  "frightened",
        -  "grappled",
        -  "incapacitated",
        -  "invisible",
        -  "paralyzed",
        -  "petrified",
        -  "poisoned",
        -  "prone",
        -  "restrained",
        -  "stunned",
        -  "unconscious",
        -  "concentrating",
        -  "grappling",
        -  "dodging",
        -  "hiding",
        -  "raging"
        -]New value: +[
        +  "blinded",
        +  "charmed",
        +  "concentration",
        +  "deafened",
        +  "exhaustion",
        +  "frightened",
        +  "grappled",
        +  "incapacitated",
        +  "invisible",
        +  "paralyzed",
        +  "petrified",
        +  "poisoned",
        +  "prone",
        +  "restrained",
        +  "stunned",
        +  "unconscious",
        +  "dazed",
        +  "grappling",
        +  "dodging",
        +  "hiding",
        +  "raging"
        +]
      • changedInput schema / properties / statBonuses / items / properties / requires / items / properties / equipSlot / description
        Previous value: -"Body slot the matched weapon must occupy. mainHand / offHand. Resolved via getRequiredSlots so two-handed grips occupy both."New value: +"Body slot the matched weapon must occupy (one of the schema's enum)."
      • changedInput schema / properties / statBonuses / items / properties / requires / items / properties / slot / description
        Previous value: -"For 'equipped' predicates: the body category to match (armor / shield / weapon)."New value: +"The equipped body category to match (one of the schema's enum)."
      • changedInput schema / properties / statBonuses / items / properties / requires / items / properties / type / description
        Previous value: -"Predicate type. 'equipped' = character-scoped (gates on what's equipped). 'attackingWeapon' = attack-scoped (gates on the current action's source weapon). 'condition' = gates on a character-state condition."New value: +"Predicate type (one of the schema's enum): what the predicate gates on."
      • changedInput schema / properties / statBonuses / items / properties / requires / items / properties / weaponProperties / description
        Previous value: -"For 'equipped' + slot:weapon OR 'attackingWeapon': weapon-property list. AND semantics — match all."New value: +"Weapon properties to match. AND semantics — match all."
      • changedInput schema / properties / statBonuses / items / properties / target / description
        Previous value: -"Stat the bonus contributes to (e.g. 'skills.Acrobatics.misc', 'attributes.strength.misc')."New value: +"Stat the bonus contributes to (e.g. 'skills.<skill>.misc', 'attributes.<ability>.misc')."
      • changedInput schema / properties / statBonuses / items / properties / trigger / description
        Previous value: -"Action-economy / cost shape of the bonus. passive / toggled / reaction / perRoll / resource / targetBound."New value: +"Action-economy / cost shape of the bonus."
      • changedInput schema / properties / statBonuses / items / properties / triggerEvent / description
        Previous value: -"Game-time event that fires the bonus (onHit / onDamage / startOfYourTurn / etc.). Absent = not event-driven (passive walker contributes whenever `requires` holds)."New value: +"Game-time event that fires the bonus (one of the schema's trigger events). Absent = not event-driven (passive walker contributes whenever `requires` holds)."
      • changedInput schema / properties / statBonuses / items / properties / valueType / enum
        Previous value: -[
        -  "fixed",
        -  "attribute",
        -  "proficiency",
        -  "level",
        -  "halfLevel",
        -  "dice",
        -  "byLevel",
        -  "attackAttribute"
        -]New value: +[
        +  "fixed",
        +  "attribute",
        +  "attackAttribute",
        +  "proficiency",
        +  "level",
        +  "halfLevel",
        +  "dice",
        +  "byLevel"
        +]
      • changedInput schema / properties / type / enum
        Previous value: -[
        -  "Ability",
        -  "Feat",
        -  "Action Card",
        -  "Hindrance",
        -  "Edge",
        -  "Class",
        -  "Background",
        -  "Race",
        -  "Species",
        -  "Ancestry",
        -  "Glossary",
        -  "Stunt",
        -  "Extra"
        -]New value: +[
        +  "Ability",
        +  "Feat",
        +  "Glossary",
        +  "Action Card",
        +  "Hindrance",
        +  "Edge",
        +  "Class",
        +  "Background",
        +  "Race",
        +  "Species",
        +  "Ancestry",
        +  "Stunt",
        +  "Extra"
        +]
    • Changedvault_update_spell80 fields changed
      • changedInput schema / properties / abilityScoreBump / properties / options / items / properties / lines / items / properties / eligible / description
        Previous value: -"Pool to choose from. Empty / absent = any of the six."New value: +"Pool to choose from. Empty / absent = any ability in the schema's abilities list."
      • changedInput schema / properties / abilityScoreBump / properties / options / items / properties / lines / items / properties / max / description
        Previous value: -"Ceiling no chosen score may exceed after the bump (ASI = 20)."New value: +"Ceiling no chosen score may exceed after the bump. The rule authoring guide's abilityScoreBump section shows the values."
      • changedInput schema / properties / abilityScoreBump / properties / options / items / properties / lines / items / properties / max / maximum
        Previous value: -9007199254740991New value: +30
      • changedInput schema / properties / abilityScoreSet / items / properties / value / maximum
        Previous value: -9007199254740991New value: +30
      • changedInput schema / properties / actions / description
        Previous value: -"PF Playtest action-economy marker (F/1/2/3/R)."New value: +"Action-cost marker, for rulesets whose spells carry one; the value is the source text."
      • changedInput schema / properties / area / description
        Previous value: -"Area of effect. shape ∈ cone|cube|cylinder|emanation|line|sphere; size (ft); width for line."New value: +"Area of effect. `shape`; `size` (ft); `width` for a line."
      • changedInput schema / properties / castingTime / description
        Previous value: -"Casting time. unit ∈ action|bonusAction|reaction|minute|hour; count for minute/hour."New value: +"Casting time. `unit`, plus `count` for a timed unit."
      • changedInput schema / properties / classes / description
        Previous value: -"Class-membership list for non-5.5e rulesets (e.g. PFRPG); 5.5e spells use `categories` instead. Free-form per ruleset."New value: +"Class-membership list for rulesets whose spells do not use `categories` (the spell authoring guide covers `categories`). Free-form per ruleset."
      • changedInput schema / properties / damageReduction / items / properties / requires / items / properties / armorCategories / description
        Previous value: -"For 'equipped' + slot:armor: armor category list (Light / Medium / Heavy). OR semantics — match any."New value: +"Armor categories to match, as the items' `armorCategory` values name them. OR semantics — match any."
      • changedInput schema / properties / damageReduction / items / properties / requires / items / properties / condition / description
        Previous value: -"For 'condition' predicates: the character-state condition to gate on (5e24 named conditions and ongoing-action states)."New value: +"For 'condition' predicates: the character-state condition to gate on (named conditions and ongoing-action states)."
      • changedInput schema / properties / damageReduction / items / properties / requires / items / properties / condition / enum
        Previous value: -[
        -  "blinded",
        -  "charmed",
        -  "dazed",
        -  "deafened",
        -  "exhaustion",
        -  "frightened",
        -  "grappled",
        -  "incapacitated",
        -  "invisible",
        -  "paralyzed",
        -  "petrified",
        -  "poisoned",
        -  "prone",
        -  "restrained",
        -  "stunned",
        -  "unconscious",
        -  "concentrating",
        -  "grappling",
        -  "dodging",
        -  "hiding",
        -  "raging"
        -]New value: +[
        +  "blinded",
        +  "charmed",
        +  "concentration",
        +  "deafened",
        +  "exhaustion",
        +  "frightened",
        +  "grappled",
        +  "incapacitated",
        +  "invisible",
        +  "paralyzed",
        +  "petrified",
        +  "poisoned",
        +  "prone",
        +  "restrained",
        +  "stunned",
        +  "unconscious",
        +  "dazed",
        +  "grappling",
        +  "dodging",
        +  "hiding",
        +  "raging"
        +]
      • changedInput schema / properties / damageReduction / items / properties / requires / items / properties / equipSlot / description
        Previous value: -"Body slot the matched weapon must occupy. mainHand / offHand. Resolved via getRequiredSlots so two-handed grips occupy both."New value: +"Body slot the matched weapon must occupy (one of the schema's enum)."
      • changedInput schema / properties / damageReduction / items / properties / requires / items / properties / slot / description
        Previous value: -"For 'equipped' predicates: the body category to match (armor / shield / weapon)."New value: +"The equipped body category to match (one of the schema's enum)."
      • changedInput schema / properties / damageReduction / items / properties / requires / items / properties / type / description
        Previous value: -"Predicate type. 'equipped' = character-scoped (gates on what's equipped). 'attackingWeapon' = attack-scoped (gates on the current action's source weapon). 'condition' = gates on a character-state condition."New value: +"Predicate type (one of the schema's enum): what the predicate gates on."
      • changedInput schema / properties / damageReduction / items / properties / requires / items / properties / weaponProperties / description
        Previous value: -"For 'equipped' + slot:weapon OR 'attackingWeapon': weapon-property list. AND semantics — match all."New value: +"Weapon properties to match. AND semantics — match all."
      • changedInput schema / properties / diceFloors / items / properties / requires / items / properties / armorCategories / description
        Previous value: -"For 'equipped' + slot:armor: armor category list (Light / Medium / Heavy). OR semantics — match any."New value: +"Armor categories to match, as the items' `armorCategory` values name them. OR semantics — match any."
      • changedInput schema / properties / diceFloors / items / properties / requires / items / properties / condition / description
        Previous value: -"For 'condition' predicates: the character-state condition to gate on (5e24 named conditions and ongoing-action states)."New value: +"For 'condition' predicates: the character-state condition to gate on (named conditions and ongoing-action states)."
      • changedInput schema / properties / diceFloors / items / properties / requires / items / properties / condition / enum
        Previous value: -[
        -  "blinded",
        -  "charmed",
        -  "dazed",
        -  "deafened",
        -  "exhaustion",
        -  "frightened",
        -  "grappled",
        -  "incapacitated",
        -  "invisible",
        -  "paralyzed",
        -  "petrified",
        -  "poisoned",
        -  "prone",
        -  "restrained",
        -  "stunned",
        -  "unconscious",
        -  "concentrating",
        -  "grappling",
        -  "dodging",
        -  "hiding",
        -  "raging"
        -]New value: +[
        +  "blinded",
        +  "charmed",
        +  "concentration",
        +  "deafened",
        +  "exhaustion",
        +  "frightened",
        +  "grappled",
        +  "incapacitated",
        +  "invisible",
        +  "paralyzed",
        +  "petrified",
        +  "poisoned",
        +  "prone",
        +  "restrained",
        +  "stunned",
        +  "unconscious",
        +  "dazed",
        +  "grappling",
        +  "dodging",
        +  "hiding",
        +  "raging"
        +]
      • changedInput schema / properties / diceFloors / items / properties / requires / items / properties / equipSlot / description
        Previous value: -"Body slot the matched weapon must occupy. mainHand / offHand. Resolved via getRequiredSlots so two-handed grips occupy both."New value: +"Body slot the matched weapon must occupy (one of the schema's enum)."
      • changedInput schema / properties / diceFloors / items / properties / requires / items / properties / slot / description
        Previous value: -"For 'equipped' predicates: the body category to match (armor / shield / weapon)."New value: +"The equipped body category to match (one of the schema's enum)."
      • changedInput schema / properties / diceFloors / items / properties / requires / items / properties / type / description
        Previous value: -"Predicate type. 'equipped' = character-scoped (gates on what's equipped). 'attackingWeapon' = attack-scoped (gates on the current action's source weapon). 'condition' = gates on a character-state condition."New value: +"Predicate type (one of the schema's enum): what the predicate gates on."
      • changedInput schema / properties / diceFloors / items / properties / requires / items / properties / weaponProperties / description
        Previous value: -"For 'equipped' + slot:weapon OR 'attackingWeapon': weapon-property list. AND semantics — match all."New value: +"Weapon properties to match. AND semantics — match all."
      • changedInput schema / properties / diceReplacements / items / properties / requires / items / properties / armorCategories / description
        Previous value: -"For 'equipped' + slot:armor: armor category list (Light / Medium / Heavy). OR semantics — match any."New value: +"Armor categories to match, as the items' `armorCategory` values name them. OR semantics — match any."
      • changedInput schema / properties / diceReplacements / items / properties / requires / items / properties / condition / description
        Previous value: -"For 'condition' predicates: the character-state condition to gate on (5e24 named conditions and ongoing-action states)."New value: +"For 'condition' predicates: the character-state condition to gate on (named conditions and ongoing-action states)."
      • changedInput schema / properties / diceReplacements / items / properties / requires / items / properties / condition / enum
        Previous value: -[
        -  "blinded",
        -  "charmed",
        -  "dazed",
        -  "deafened",
        -  "exhaustion",
        -  "frightened",
        -  "grappled",
        -  "incapacitated",
        -  "invisible",
        -  "paralyzed",
        -  "petrified",
        -  "poisoned",
        -  "prone",
        -  "restrained",
        -  "stunned",
        -  "unconscious",
        -  "concentrating",
        -  "grappling",
        -  "dodging",
        -  "hiding",
        -  "raging"
        -]New value: +[
        +  "blinded",
        +  "charmed",
        +  "concentration",
        +  "deafened",
        +  "exhaustion",
        +  "frightened",
        +  "grappled",
        +  "incapacitated",
        +  "invisible",
        +  "paralyzed",
        +  "petrified",
        +  "poisoned",
        +  "prone",
        +  "restrained",
        +  "stunned",
        +  "unconscious",
        +  "dazed",
        +  "grappling",
        +  "dodging",
        +  "hiding",
        +  "raging"
        +]
      • changedInput schema / properties / diceReplacements / items / properties / requires / items / properties / equipSlot / description
        Previous value: -"Body slot the matched weapon must occupy. mainHand / offHand. Resolved via getRequiredSlots so two-handed grips occupy both."New value: +"Body slot the matched weapon must occupy (one of the schema's enum)."
      • changedInput schema / properties / diceReplacements / items / properties / requires / items / properties / slot / description
        Previous value: -"For 'equipped' predicates: the body category to match (armor / shield / weapon)."New value: +"The equipped body category to match (one of the schema's enum)."
      • changedInput schema / properties / diceReplacements / items / properties / requires / items / properties / type / description
        Previous value: -"Predicate type. 'equipped' = character-scoped (gates on what's equipped). 'attackingWeapon' = attack-scoped (gates on the current action's source weapon). 'condition' = gates on a character-state condition."New value: +"Predicate type (one of the schema's enum): what the predicate gates on."
      • changedInput schema / properties / diceReplacements / items / properties / requires / items / properties / weaponProperties / description
        Previous value: -"For 'equipped' + slot:weapon OR 'attackingWeapon': weapon-property list. AND semantics — match all."New value: +"Weapon properties to match. AND semantics — match all."
      • changedInput schema / properties / duration / description
        Previous value: -"Spell duration. unit ∈ instantaneous | round | minute | hour | day | untilDispelled | untilDispelledOrTriggered | special; count for timed units; concentration flag; upTo flag for a non-concentration capped duration (\"Up to 1 minute\")."New value: +"Spell duration. `unit`; `count` for a timed unit; concentration flag; upTo flag for a non-concentration capped duration (\"Up to 1 minute\")."
      • changedInput schema / properties / forcedMovement / items / properties / requires / items / properties / armorCategories / description
        Previous value: -"For 'equipped' + slot:armor: armor category list (Light / Medium / Heavy). OR semantics — match any."New value: +"Armor categories to match, as the items' `armorCategory` values name them. OR semantics — match any."
      • changedInput schema / properties / forcedMovement / items / properties / requires / items / properties / condition / description
        Previous value: -"For 'condition' predicates: the character-state condition to gate on (5e24 named conditions and ongoing-action states)."New value: +"For 'condition' predicates: the character-state condition to gate on (named conditions and ongoing-action states)."
      • changedInput schema / properties / forcedMovement / items / properties / requires / items / properties / condition / enum
        Previous value: -[
        -  "blinded",
        -  "charmed",
        -  "dazed",
        -  "deafened",
        -  "exhaustion",
        -  "frightened",
        -  "grappled",
        -  "incapacitated",
        -  "invisible",
        -  "paralyzed",
        -  "petrified",
        -  "poisoned",
        -  "prone",
        -  "restrained",
        -  "stunned",
        -  "unconscious",
        -  "concentrating",
        -  "grappling",
        -  "dodging",
        -  "hiding",
        -  "raging"
        -]New value: +[
        +  "blinded",
        +  "charmed",
        +  "concentration",
        +  "deafened",
        +  "exhaustion",
        +  "frightened",
        +  "grappled",
        +  "incapacitated",
        +  "invisible",
        +  "paralyzed",
        +  "petrified",
        +  "poisoned",
        +  "prone",
        +  "restrained",
        +  "stunned",
        +  "unconscious",
        +  "dazed",
        +  "grappling",
        +  "dodging",
        +  "hiding",
        +  "raging"
        +]
      • changedInput schema / properties / forcedMovement / items / properties / requires / items / properties / equipSlot / description
        Previous value: -"Body slot the matched weapon must occupy. mainHand / offHand. Resolved via getRequiredSlots so two-handed grips occupy both."New value: +"Body slot the matched weapon must occupy (one of the schema's enum)."
      • changedInput schema / properties / forcedMovement / items / properties / requires / items / properties / slot / description
        Previous value: -"For 'equipped' predicates: the body category to match (armor / shield / weapon)."New value: +"The equipped body category to match (one of the schema's enum)."
      • changedInput schema / properties / forcedMovement / items / properties / requires / items / properties / type / description
        Previous value: -"Predicate type. 'equipped' = character-scoped (gates on what's equipped). 'attackingWeapon' = attack-scoped (gates on the current action's source weapon). 'condition' = gates on a character-state condition."New value: +"Predicate type (one of the schema's enum): what the predicate gates on."
      • changedInput schema / properties / forcedMovement / items / properties / requires / items / properties / weaponProperties / description
        Previous value: -"For 'equipped' + slot:weapon OR 'attackingWeapon': weapon-property list. AND semantics — match all."New value: +"Weapon properties to match. AND semantics — match all."
      • changedInput schema / properties / higherLevel / description
        Previous value: -"Higher-Level / cantrip-scaling text (what changes when cast with a higher slot)."New value: +"Scaling text: what changes when the spell is cast at a higher level or scales with the caster, source text."
      • changedInput schema / properties / level / description
        Previous value: -"Spell level. 0 for cantrips; 1–9 for leveled spells (5e/5e24)."New value: +"Spell level, within the schema's range. The spell authoring guide gives the convention."
      • changedInput schema / properties / level / maximum
        Previous value: -9007199254740991New value: +9
      • changedInput schema / properties / level / minimum
        Previous value: --9007199254740991New value: +0
      • changedInput schema / properties / prerequisites / items / properties / abilities / description
        Previous value: -"For abilityScore: ANY listed ability meeting `min` satisfies ('Str or Dex 13+')."New value: +"For abilityScore: ANY listed ability meeting `min` satisfies."
      • changedInput schema / properties / prerequisites / items / properties / proficiency / description
        Previous value: -"For proficiency: the proficiency name (e.g. 'Martial', 'Stealth')."New value: +"For proficiency: the proficiency name, as the ruleset names it."
      • changedInput schema / properties / prerequisites / items / properties / proficiencyType / enum
        Previous value: -[
        -  "skill",
        -  "tool",
        -  "weapon",
        -  "armor",
        -  "save",
        -  "language"
        -]New value: +[
        +  "skill",
        +  "tool",
        +  "save",
        +  "weapon",
        +  "armor",
        +  "language"
        +]
      • changedInput schema / properties / prerequisites / items / properties / type / description
        Previous value: -"Predicate kind: level / abilityScore / rule / spell / proficiency / spellcasting. (A class is required via a `rule` predicate pointing at the class rule.)"New value: +"Predicate kind. (A class is required via a `rule` predicate pointing at the class rule.)"
      • changedInput schema / properties / range / description
        Previous value: -"Range. kind ∈ self|touch|ranged|sight|unlimited|special; distance for ranged; unit ∈ feet|miles (default feet)."New value: +"Range. `kind`; `distance` and its `unit` for a ranged spell (absent unit = feet)."
      • changedInput schema / properties / rank / description
        Previous value: -"PFRPG2 rank field. Free-form."New value: +"Rank, for rulesets whose spells carry one. Free-form."
      • changedInput schema / properties / reactionTrigger / description
        Previous value: -"When castingTime.unit is 'reaction', the trigger text ('which you take when…')."New value: +"For a casting time taken in response to a trigger, the trigger text, source text."
      • changedInput schema / properties / recurringDamage / items / properties / requires / items / properties / armorCategories / description
        Previous value: -"For 'equipped' + slot:armor: armor category list (Light / Medium / Heavy). OR semantics — match any."New value: +"Armor categories to match, as the items' `armorCategory` values name them. OR semantics — match any."
      • changedInput schema / properties / recurringDamage / items / properties / requires / items / properties / condition / description
        Previous value: -"For 'condition' predicates: the character-state condition to gate on (5e24 named conditions and ongoing-action states)."New value: +"For 'condition' predicates: the character-state condition to gate on (named conditions and ongoing-action states)."
      • changedInput schema / properties / recurringDamage / items / properties / requires / items / properties / condition / enum
        Previous value: -[
        -  "blinded",
        -  "charmed",
        -  "dazed",
        -  "deafened",
        -  "exhaustion",
        -  "frightened",
        -  "grappled",
        -  "incapacitated",
        -  "invisible",
        -  "paralyzed",
        -  "petrified",
        -  "poisoned",
        -  "prone",
        -  "restrained",
        -  "stunned",
        -  "unconscious",
        -  "concentrating",
        -  "grappling",
        -  "dodging",
        -  "hiding",
        -  "raging"
        -]New value: +[
        +  "blinded",
        +  "charmed",
        +  "concentration",
        +  "deafened",
        +  "exhaustion",
        +  "frightened",
        +  "grappled",
        +  "incapacitated",
        +  "invisible",
        +  "paralyzed",
        +  "petrified",
        +  "poisoned",
        +  "prone",
        +  "restrained",
        +  "stunned",
        +  "unconscious",
        +  "dazed",
        +  "grappling",
        +  "dodging",
        +  "hiding",
        +  "raging"
        +]
      • changedInput schema / properties / recurringDamage / items / properties / requires / items / properties / equipSlot / description
        Previous value: -"Body slot the matched weapon must occupy. mainHand / offHand. Resolved via getRequiredSlots so two-handed grips occupy both."New value: +"Body slot the matched weapon must occupy (one of the schema's enum)."
      • changedInput schema / properties / recurringDamage / items / properties / requires / items / properties / slot / description
        Previous value: -"For 'equipped' predicates: the body category to match (armor / shield / weapon)."New value: +"The equipped body category to match (one of the schema's enum)."
      • changedInput schema / properties / recurringDamage / items / properties / requires / items / properties / type / description
        Previous value: -"Predicate type. 'equipped' = character-scoped (gates on what's equipped). 'attackingWeapon' = attack-scoped (gates on the current action's source weapon). 'condition' = gates on a character-state condition."New value: +"Predicate type (one of the schema's enum): what the predicate gates on."
      • changedInput schema / properties / recurringDamage / items / properties / requires / items / properties / weaponProperties / description
        Previous value: -"For 'equipped' + slot:weapon OR 'attackingWeapon': weapon-property list. AND semantics — match all."New value: +"Weapon properties to match. AND semantics — match all."
      • changedInput schema / properties / resistances / items / properties / range / description
        Previous value: -"Aura radius in feet for ally/any-targeted resistances (Warding Aura's 10 ft.). Absent = self-only."New value: +"Aura radius in feet for ally/any-targeted resistances. Absent = self-only."
      • changedInput schema / properties / ritual / description
        Previous value: -"5.5e ritual tag — the spell can be cast as a ritual (no spell slot)."New value: +"Ritual tag: the spell can be cast as a ritual."
      • changedInput schema / properties / rollMods / items / properties / requires / items / properties / armorCategories / description
        Previous value: -"For 'equipped' + slot:armor: armor category list (Light / Medium / Heavy). OR semantics — match any."New value: +"Armor categories to match, as the items' `armorCategory` values name them. OR semantics — match any."
      • changedInput schema / properties / rollMods / items / properties / requires / items / properties / condition / description
        Previous value: -"For 'condition' predicates: the character-state condition to gate on (5e24 named conditions and ongoing-action states)."New value: +"For 'condition' predicates: the character-state condition to gate on (named conditions and ongoing-action states)."
      • changedInput schema / properties / rollMods / items / properties / requires / items / properties / condition / enum
        Previous value: -[
        -  "blinded",
        -  "charmed",
        -  "dazed",
        -  "deafened",
        -  "exhaustion",
        -  "frightened",
        -  "grappled",
        -  "incapacitated",
        -  "invisible",
        -  "paralyzed",
        -  "petrified",
        -  "poisoned",
        -  "prone",
        -  "restrained",
        -  "stunned",
        -  "unconscious",
        -  "concentrating",
        -  "grappling",
        -  "dodging",
        -  "hiding",
        -  "raging"
        -]New value: +[
        +  "blinded",
        +  "charmed",
        +  "concentration",
        +  "deafened",
        +  "exhaustion",
        +  "frightened",
        +  "grappled",
        +  "incapacitated",
        +  "invisible",
        +  "paralyzed",
        +  "petrified",
        +  "poisoned",
        +  "prone",
        +  "restrained",
        +  "stunned",
        +  "unconscious",
        +  "dazed",
        +  "grappling",
        +  "dodging",
        +  "hiding",
        +  "raging"
        +]
      • changedInput schema / properties / rollMods / items / properties / requires / items / properties / equipSlot / description
        Previous value: -"Body slot the matched weapon must occupy. mainHand / offHand. Resolved via getRequiredSlots so two-handed grips occupy both."New value: +"Body slot the matched weapon must occupy (one of the schema's enum)."
      • changedInput schema / properties / rollMods / items / properties / requires / items / properties / slot / description
        Previous value: -"For 'equipped' predicates: the body category to match (armor / shield / weapon)."New value: +"The equipped body category to match (one of the schema's enum)."
      • changedInput schema / properties / rollMods / items / properties / requires / items / properties / type / description
        Previous value: -"Predicate type. 'equipped' = character-scoped (gates on what's equipped). 'attackingWeapon' = attack-scoped (gates on the current action's source weapon). 'condition' = gates on a character-state condition."New value: +"Predicate type (one of the schema's enum): what the predicate gates on."
      • changedInput schema / properties / rollMods / items / properties / requires / items / properties / weaponProperties / description
        Previous value: -"For 'equipped' + slot:weapon OR 'attackingWeapon': weapon-property list. AND semantics — match all."New value: +"Weapon properties to match. AND semantics — match all."
      • changedInput schema / properties / ruleset / description
        Previous value: -"Ruleset code (e.g. '5th Edition', '5e24', 'PFRPG', 'Savage Worlds')."New value: +"Ruleset code, from list_rulesets."
      • changedInput schema / properties / school / description
        Previous value: -"Spell school (Abjuration, Conjuration, Divination, Enchantment, Evocation, Illusion, Necromancy, Transmutation)."New value: +"Spell school name."
      • changedInput schema / properties / statBonuses / items / properties / durationCount / description
        Previous value: -"Numeric count paired with durationUnit (e.g. count: 3, unit: 'round')."New value: +"Numeric count paired with durationUnit."
      • changedInput schema / properties / statBonuses / items / properties / range / description
        Previous value: -"Aura radius in feet for ally/any-audience bonuses (Aura of Protection's 10 ft.). Absent = no range filter."New value: +"Aura radius in feet for ally/any-audience bonuses. Absent = no range filter."
      • changedInput schema / properties / statBonuses / items / properties / requires / items / properties / armorCategories / description
        Previous value: -"For 'equipped' + slot:armor: armor category list (Light / Medium / Heavy). OR semantics — match any."New value: +"Armor categories to match, as the items' `armorCategory` values name them. OR semantics — match any."
      • changedInput schema / properties / statBonuses / items / properties / requires / items / properties / condition / description
        Previous value: -"For 'condition' predicates: the character-state condition to gate on (5e24 named conditions and ongoing-action states)."New value: +"For 'condition' predicates: the character-state condition to gate on (named conditions and ongoing-action states)."
      • changedInput schema / properties / statBonuses / items / properties / requires / items / properties / condition / enum
        Previous value: -[
        -  "blinded",
        -  "charmed",
        -  "dazed",
        -  "deafened",
        -  "exhaustion",
        -  "frightened",
        -  "grappled",
        -  "incapacitated",
        -  "invisible",
        -  "paralyzed",
        -  "petrified",
        -  "poisoned",
        -  "prone",
        -  "restrained",
        -  "stunned",
        -  "unconscious",
        -  "concentrating",
        -  "grappling",
        -  "dodging",
        -  "hiding",
        -  "raging"
        -]New value: +[
        +  "blinded",
        +  "charmed",
        +  "concentration",
        +  "deafened",
        +  "exhaustion",
        +  "frightened",
        +  "grappled",
        +  "incapacitated",
        +  "invisible",
        +  "paralyzed",
        +  "petrified",
        +  "poisoned",
        +  "prone",
        +  "restrained",
        +  "stunned",
        +  "unconscious",
        +  "dazed",
        +  "grappling",
        +  "dodging",
        +  "hiding",
        +  "raging"
        +]
      • changedInput schema / properties / statBonuses / items / properties / requires / items / properties / equipSlot / description
        Previous value: -"Body slot the matched weapon must occupy. mainHand / offHand. Resolved via getRequiredSlots so two-handed grips occupy both."New value: +"Body slot the matched weapon must occupy (one of the schema's enum)."
      • changedInput schema / properties / statBonuses / items / properties / requires / items / properties / slot / description
        Previous value: -"For 'equipped' predicates: the body category to match (armor / shield / weapon)."New value: +"The equipped body category to match (one of the schema's enum)."
      • changedInput schema / properties / statBonuses / items / properties / requires / items / properties / type / description
        Previous value: -"Predicate type. 'equipped' = character-scoped (gates on what's equipped). 'attackingWeapon' = attack-scoped (gates on the current action's source weapon). 'condition' = gates on a character-state condition."New value: +"Predicate type (one of the schema's enum): what the predicate gates on."
      • changedInput schema / properties / statBonuses / items / properties / requires / items / properties / weaponProperties / description
        Previous value: -"For 'equipped' + slot:weapon OR 'attackingWeapon': weapon-property list. AND semantics — match all."New value: +"Weapon properties to match. AND semantics — match all."
      • changedInput schema / properties / statBonuses / items / properties / target / description
        Previous value: -"Stat the bonus contributes to (e.g. 'skills.Acrobatics.misc', 'attributes.strength.misc')."New value: +"Stat the bonus contributes to (e.g. 'skills.<skill>.misc', 'attributes.<ability>.misc')."
      • changedInput schema / properties / statBonuses / items / properties / trigger / description
        Previous value: -"Action-economy / cost shape of the bonus. passive / toggled / reaction / perRoll / resource / targetBound."New value: +"Action-economy / cost shape of the bonus."
      • changedInput schema / properties / statBonuses / items / properties / triggerEvent / description
        Previous value: -"Game-time event that fires the bonus (onHit / onDamage / startOfYourTurn / etc.). Absent = not event-driven (passive walker contributes whenever `requires` holds)."New value: +"Game-time event that fires the bonus (one of the schema's trigger events). Absent = not event-driven (passive walker contributes whenever `requires` holds)."
      • changedInput schema / properties / statBonuses / items / properties / valueType / enum
        Previous value: -[
        -  "fixed",
        -  "attribute",
        -  "proficiency",
        -  "level",
        -  "halfLevel",
        -  "dice",
        -  "byLevel",
        -  "attackAttribute"
        -]New value: +[
        +  "fixed",
        +  "attribute",
        +  "attackAttribute",
        +  "proficiency",
        +  "level",
        +  "halfLevel",
        +  "dice",
        +  "byLevel"
        +]
      • changedInput schema / properties / type / description
        Previous value: -"Spell type. 5e / 5e24 use 'Spell'; Savage Worlds uses 'Power'. Required at create."New value: +"Spell type (the ruleset's name for a spell). Required at create."
  3. 29 tool updates
    • Changedimagine_create_adventure23 fields changed
      • addedInput schema / $schema
        Added value: +"http://json-schema.org/draft-07/schema#"
      • addedInput schema / additionalProperties
        Added value: +{}
      • addedInput schema / properties / active
        Added value: +{
        +  "type": "boolean"
        +}
      • addedInput schema / properties / barImages
        Added value: +{
        +  "description": "GM-curated reference images displayed in a fixed bar across the adventure (maps, handouts, NPC portraits).",
        +  "items": {
        +    "additionalProperties": {},
        +    "properties": {
        +      "name": {
        +        "type": "string"
        +      },
        +      "url": {
        +        "description": "Image URL. Required by Mongoose; gateway leaves it optional so a missing url surfaces as a clean backend error.",
        +        "type": "string"
        +      }
        +    },
        +    "type": "object"
        +  },
        +  "type": "array"
        +}
      • addedInput schema / properties / companions
        Added value: +{
        +  "items": {
        +    "additionalProperties": {},
        +    "properties": {
        +      "name": {
        +        "type": "string"
        +      },
        +      "type": {
        +        "type": "string"
        +      },
        +      "vaultId": {
        +        "description": "Vault entity id (character/monster). Required by Mongoose.",
        +        "type": "string"
        +      }
        +    },
        +    "type": "object"
        +  },
        +  "type": "array"
        +}
      • addedInput schema / properties / contentWarnings
        Added value: +{
        +  "items": {
        +    "type": "string"
        +  },
        +  "type": "array"
        +}
      • addedInput schema / properties / description
        Added value: +{
        +  "description": "Full adventure description. Markdown supported.",
        +  "type": "string"
        +}
      • addedInput schema / properties / estimatedHours
        Added value: +{
        +  "type": "number"
        +}
      • addedInput schema / properties / image
        Added value: +{
        +  "description": "Header image URL.",
        +  "type": "string"
        +}
      • addedInput schema / properties / imageCarousel
        Added value: +{
        +  "items": {
        +    "type": "string"
        +  },
        +  "type": "array"
        +}
      • addedInput schema / properties / keywords
        Added value: +{
        +  "description": "Comma-separated keyword string used by adventure-wide tag/search.",
        +  "type": "string"
        +}
      • addedInput schema / properties / level
        Added value: +{
        +  "additionalProperties": {},
        +  "description": "Recommended character level range. Each side optional; null means unset.",
        +  "properties": {
        +    "max": {
        +      "type": "number"
        +    },
        +    "min": {
        +      "type": "number"
        +    }
        +  },
        +  "type": "object"
        +}
      • addedInput schema / properties / link
        Added value: +{
        +  "description": "URL-safe slug. Lowercase letters, numbers, and hyphens. Imagine auto-suggests at create time when omitted.",
        +  "type": "string"
        +}
      • addedInput schema / properties / name
        Added value: +{
        +  "description": "Adventure name. Required.",
        +  "minLength": 1,
        +  "type": "string"
        +}
      • addedInput schema / properties / partySize
        Added value: +{
        +  "additionalProperties": {},
        +  "description": "Recommended party size range.",
        +  "properties": {
        +    "max": {
        +      "type": "number"
        +    },
        +    "min": {
        +      "type": "number"
        +    }
        +  },
        +  "type": "object"
        +}
      • addedInput schema / properties / public
        Added value: +{
        +  "type": "boolean"
        +}
      • addedInput schema / properties / publisher
        Added value: +{
        +  "type": "string"
        +}
      • addedInput schema / properties / ruleset
        Added value: +{
        +  "description": "Ruleset code. Required at create time; imagine has no default ruleset for adventures.",
        +  "minLength": 1,
        +  "type": "string"
        +}
      • addedInput schema / properties / status
        Added value: +{
        +  "enum": [
        +    "draft",
        +    "playtest",
        +    "published"
        +  ],
        +  "type": "string"
        +}
      • addedInput schema / properties / summary
        Added value: +{
        +  "description": "Short summary; capped at 150 characters by imagine.",
        +  "maxLength": 150,
        +  "type": "string"
        +}
      • addedInput schema / properties / version
        Added value: +{
        +  "type": "string"
        +}
      • addedInput schema / properties / world
        Added value: +{
        +  "description": "Optional World _id this adventure belongs to.",
        +  "minLength": 1,
        +  "type": "string"
        +}
      • addedInput schema / required
        Added value: +[
        +  "name",
        +  "ruleset"
        +]
    • Changedimagine_create_adventure_page27 fields changed
      • addedInput schema / $schema
        Added value: +"http://json-schema.org/draft-07/schema#"
      • addedInput schema / additionalProperties
        Added value: +{}
      • addedInput schema / properties / active
        Added value: +{
        +  "type": "boolean"
        +}
      • addedInput schema / properties / adventureId
        Added value: +{
        +  "description": "Adventure to add the page to.",
        +  "minLength": 1,
        +  "type": "string"
        +}
      • addedInput schema / properties / aliases
        Added value: +{
        +  "items": {
        +    "type": "string"
        +  },
        +  "type": "array"
        +}
      • addedInput schema / properties / content
        Added value: +{
        +  "description": "Page body in markdown. Imagine renders this verbatim. WARNING: REPLACED wholesale on update; prefer imagine_replace_in_adventure_page for surgical edits.",
        +  "type": "string"
        +}
      • addedInput schema / properties / details
        Added value: +{
        +  "description": "Label/value list of arbitrary metadata pairs.",
        +  "items": {
        +    "additionalProperties": {},
        +    "properties": {
        +      "label": {
        +        "type": "string"
        +      },
        +      "value": {
        +        "type": "string"
        +      }
        +    },
        +    "type": "object"
        +  },
        +  "type": "array"
        +}
      • addedInput schema / properties / documentType
        Added value: +{
        +  "description": "Structural type. Drives shape-specific fields.",
        +  "enum": [
        +    "generic",
        +    "act",
        +    "scene",
        +    "location",
        +    "character",
        +    "handout",
        +    "lore",
        +    "appendix",
        +    "map"
        +  ],
        +  "type": "string"
        +}
      • addedInput schema / properties / duration
        Added value: +{
        +  "type": "string"
        +}
      • addedInput schema / properties / goal
        Added value: +{
        +  "type": "string"
        +}
      • addedInput schema / properties / image
        Added value: +{
        +  "type": "string"
        +}
      • addedInput schema / properties / link
        Added value: +{
        +  "description": "URL-safe slug. Lowercase letters, numbers, hyphens, slashes.",
        +  "type": "string"
        +}
      • addedInput schema / properties / locationKey
        Added value: +{
        +  "type": "string"
        +}
      • addedInput schema / properties / map
        Added value: +{
        +  "anyOf": [
        +    {
        +      "type": "string"
        +    },
        +    {
        +      "type": "null"
        +    }
        +  ],
        +  "description": "Location shape: Mongo `_id` of the Map this location belongs to. Pass null to clear."
        +}
      • addedInput schema / properties / mapPin
        Added value: +{
        +  "type": "string"
        +}
      • addedInput schema / properties / menuOrder
        Added value: +{
        +  "maximum": 9007199254740991,
        +  "minimum": -9007199254740991,
        +  "type": "integer"
        +}
      • addedInput schema / properties / name
        Added value: +{
        +  "description": "Page name. Required.",
        +  "minLength": 1,
        +  "type": "string"
        +}
      • addedInput schema / properties / outboundLinks
        Added value: +{
        +  "description": "AdventurePage ids this page links to. Imagine recomputes this on save when missing; explicit values override.",
        +  "items": {
        +    "description": "Mongo `_id` reference (24-character hex string).",
        +    "minLength": 1,
        +    "type": "string"
        +  },
        +  "type": "array"
        +}
      • addedInput schema / properties / parentId
        Added value: +{
        +  "description": "Mongo `_id` of the parent page (for tree structure).",
        +  "type": "string"
        +}
      • addedInput schema / properties / relationships
        Added value: +{
        +  "description": "Sibling AdventurePage ids the page relates to.",
        +  "items": {
        +    "description": "Mongo `_id` reference (24-character hex string).",
        +    "minLength": 1,
        +    "type": "string"
        +  },
        +  "type": "array"
        +}
      • addedInput schema / properties / summary
        Added value: +{
        +  "description": "Short page summary. Max 150 characters (matches the AdventurePage Mongoose schema's maxlength). Sibling Adventure and WorldPage summaries share the same cap; legacy World summaries cap at 255 (cross-app convention).",
        +  "maxLength": 150,
        +  "type": "string"
        +}
      • addedInput schema / properties / tags
        Added value: +{
        +  "description": "Tag list. Imagine stores as a comma-separated `keywords` string.",
        +  "items": {
        +    "type": "string"
        +  },
        +  "type": "array"
        +}
      • addedInput schema / properties / template
        Added value: +{
        +  "description": "Template id when authored from a template.",
        +  "type": "string"
        +}
      • addedInput schema / properties / treasureRefs
        Added value: +{
        +  "description": "Treasure entries. Same shape as `vaultRefs`.",
        +  "items": {
        +    "additionalProperties": {},
        +    "properties": {
        +      "count": {
        +        "type": "number"
        +      },
        +      "name": {
        +        "type": "string"
        +      },
        +      "type": {
        +        "type": "string"
        +      },
        +      "vaultId": {
        +        "type": "string"
        +      }
        +    },
        +    "type": "object"
        +  },
        +  "type": "array"
        +}
      • addedInput schema / properties / vaultRefs
        Added value: +{
        +  "description": "Participants on the page. Each entry `{ vaultId?, type?, count?, name? }`.",
        +  "items": {
        +    "additionalProperties": {},
        +    "properties": {
        +      "count": {
        +        "type": "number"
        +      },
        +      "name": {
        +        "type": "string"
        +      },
        +      "type": {
        +        "type": "string"
        +      },
        +      "vaultId": {
        +        "type": "string"
        +      }
        +    },
        +    "type": "object"
        +  },
        +  "type": "array"
        +}
      • addedInput schema / properties / worldPageRefs
        Added value: +{
        +  "description": "Mongo `_id` list of referenced world pages.",
        +  "items": {
        +    "description": "Mongo `_id` reference (24-character hex string).",
        +    "minLength": 1,
        +    "type": "string"
        +  },
        +  "type": "array"
        +}
      • addedInput schema / required
        Added value: +[
        +  "adventureId",
        +  "name"
        +]
    • Changedimagine_create_world18 fields changed
      • addedInput schema / $schema
        Added value: +"http://json-schema.org/draft-07/schema#"
      • addedInput schema / additionalProperties
        Added value: +{}
      • addedInput schema / properties / active
        Added value: +{
        +  "type": "boolean"
        +}
      • addedInput schema / properties / calendar
        Added value: +{
        +  "additionalProperties": {},
        +  "description": "Optional calendar definition (months[] + eras[]).",
        +  "properties": {
        +    "eras": {
        +      "items": {
        +        "additionalProperties": {},
        +        "properties": {
        +          "name": {
        +            "type": "string"
        +          },
        +          "order": {
        +            "type": "number"
        +          }
        +        },
        +        "type": "object"
        +      },
        +      "type": "array"
        +    },
        +    "months": {
        +      "items": {
        +        "additionalProperties": {},
        +        "properties": {
        +          "name": {
        +            "type": "string"
        +          },
        +          "order": {
        +            "type": "number"
        +          }
        +        },
        +        "type": "object"
        +      },
        +      "type": "array"
        +    }
        +  },
        +  "type": "object"
        +}
      • addedInput schema / properties / customDomain
        Added value: +{
        +  "description": "Optional custom domain pointing at the world's public site.",
        +  "type": "string"
        +}
      • addedInput schema / properties / description
        Added value: +{
        +  "description": "Full world description. Markdown supported.",
        +  "type": "string"
        +}
      • addedInput schema / properties / favicon
        Added value: +{
        +  "type": "string"
        +}
      • addedInput schema / properties / image
        Added value: +{
        +  "type": "string"
        +}
      • addedInput schema / properties / imageCarousel
        Added value: +{
        +  "items": {
        +    "type": "string"
        +  },
        +  "type": "array"
        +}
      • addedInput schema / properties / isExampleWorld
        Added value: +{
        +  "type": "boolean"
        +}
      • addedInput schema / properties / keywords
        Added value: +{
        +  "type": "string"
        +}
      • addedInput schema / properties / link
        Added value: +{
        +  "description": "URL-safe slug for the world (lowercase letters, digits, hyphens). Imagine auto-suggests at create time when omitted.",
        +  "type": "string"
        +}
      • addedInput schema / properties / menu
        Added value: +{
        +  "description": "Site menu entries — label + optional link/pageId/order.",
        +  "items": {
        +    "additionalProperties": {},
        +    "properties": {
        +      "label": {
        +        "description": "Required by Mongoose.",
        +        "type": "string"
        +      },
        +      "link": {
        +        "type": "string"
        +      },
        +      "order": {
        +        "type": "number"
        +      },
        +      "pageId": {
        +        "description": "Mongo `_id` reference (24-character hex string).",
        +        "minLength": 1,
        +        "type": "string"
        +      }
        +    },
        +    "type": "object"
        +  },
        +  "type": "array"
        +}
      • addedInput schema / properties / name
        Added value: +{
        +  "description": "World name. Required.",
        +  "minLength": 1,
        +  "type": "string"
        +}
      • addedInput schema / properties / public
        Added value: +{
        +  "description": "Whether the world is public. Only Premium, VIP, and admin accounts can change whether a world is public; the server refuses the change from anyone else. A new world is public unless set otherwise.",
        +  "type": "boolean"
        +}
      • addedInput schema / properties / showInvite
        Added value: +{
        +  "type": "boolean"
        +}
      • addedInput schema / properties / summary
        Added value: +{
        +  "description": "Short summary; capped at 255 characters. Cross-app convention (per dev-sites/AGENTS.md); the Mongoose World schema still accepts up to 500 as a legacy inconsistency being migrated, but new authoring should keep summaries under 255.",
        +  "maxLength": 255,
        +  "type": "string"
        +}
      • addedInput schema / required
        Added value: +[
        +  "name"
        +]
    • Changedimagine_create_world_page31 fields changed
      • addedInput schema / $schema
        Added value: +"http://json-schema.org/draft-07/schema#"
      • addedInput schema / additionalProperties
        Added value: +{}
      • addedInput schema / properties / active
        Added value: +{
        +  "type": "boolean"
        +}
      • addedInput schema / properties / aliases
        Added value: +{
        +  "items": {
        +    "type": "string"
        +  },
        +  "type": "array"
        +}
      • addedInput schema / properties / content
        Added value: +{
        +  "description": "Page body in markdown. Imagine renders this verbatim. REPLACED wholesale on update.",
        +  "type": "string"
        +}
      • addedInput schema / properties / details
        Added value: +{
        +  "items": {
        +    "additionalProperties": {},
        +    "properties": {
        +      "label": {
        +        "type": "string"
        +      },
        +      "value": {
        +        "type": "string"
        +      }
        +    },
        +    "type": "object"
        +  },
        +  "type": "array"
        +}
      • addedInput schema / properties / documentType
        Added value: +{
        +  "enum": [
        +    "generic",
        +    "character",
        +    "location",
        +    "organization",
        +    "event",
        +    "lore",
        +    "religion",
        +    "cosmology"
        +  ],
        +  "type": "string"
        +}
      • addedInput schema / properties / eventDate
        Added value: +{
        +  "additionalProperties": {},
        +  "description": "Optional in-world event date for chronology-shape pages.",
        +  "properties": {
        +    "day": {
        +      "maximum": 9007199254740991,
        +      "minimum": -9007199254740991,
        +      "type": "integer"
        +    },
        +    "eraId": {
        +      "description": "Mongo `_id` reference (24-character hex string).",
        +      "minLength": 1,
        +      "type": "string"
        +    },
        +    "label": {
        +      "type": "string"
        +    },
        +    "monthId": {
        +      "description": "Mongo `_id` reference (24-character hex string).",
        +      "minLength": 1,
        +      "type": "string"
        +    },
        +    "year": {
        +      "maximum": 9007199254740991,
        +      "minimum": -9007199254740991,
        +      "type": "integer"
        +    }
        +  },
        +  "type": "object"
        +}
      • addedInput schema / properties / gmNotes
        Added value: +{
        +  "description": "GM-only notes attached to the page.",
        +  "type": "string"
        +}
      • addedInput schema / properties / image
        Added value: +{
        +  "type": "string"
        +}
      • addedInput schema / properties / isWorldChild
        Added value: +{
        +  "type": "boolean"
        +}
      • addedInput schema / properties / link
        Added value: +{
        +  "description": "URL-safe slug. Lowercase letters, numbers, hyphens, slashes.",
        +  "type": "string"
        +}
      • addedInput schema / properties / maskName
        Added value: +{
        +  "description": "What non-contributors see instead of the page's name while visibility is 'masked'. Empty renders as 'Redacted'.",
        +  "type": "string"
        +}
      • addedInput schema / properties / maskSummary
        Added value: +{
        +  "description": "Optional teaser non-contributors see on the masked page; the real summary and content stay hidden. Max 255 characters.",
        +  "maxLength": 255,
        +  "type": "string"
        +}
      • addedInput schema / properties / menuLabel
        Added value: +{
        +  "type": "string"
        +}
      • addedInput schema / properties / menuOrder
        Added value: +{
        +  "maximum": 9007199254740991,
        +  "minimum": -9007199254740991,
        +  "type": "integer"
        +}
      • addedInput schema / properties / name
        Added value: +{
        +  "description": "Page name. Required.",
        +  "minLength": 1,
        +  "type": "string"
        +}
      • addedInput schema / properties / outboundLinks
        Added value: +{
        +  "items": {
        +    "description": "Mongo `_id` reference (24-character hex string).",
        +    "minLength": 1,
        +    "type": "string"
        +  },
        +  "type": "array"
        +}
      • addedInput schema / properties / parentId
        Added value: +{
        +  "description": "Mongo `_id` of the parent world page (tree structure).",
        +  "type": "string"
        +}
      • addedInput schema / properties / playCampaignCharacters
        Added value: +{
        +  "items": {
        +    "additionalProperties": {},
        +    "properties": {
        +      "campaignId": {
        +        "type": "string"
        +      },
        +      "playCharacterId": {
        +        "description": "Mongo `_id` reference (24-character hex string).",
        +        "minLength": 1,
        +        "type": "string"
        +      }
        +    },
        +    "type": "object"
        +  },
        +  "type": "array"
        +}
      • addedInput schema / properties / relationships
        Added value: +{
        +  "items": {
        +    "description": "Mongo `_id` reference (24-character hex string).",
        +    "minLength": 1,
        +    "type": "string"
        +  },
        +  "type": "array"
        +}
      • addedInput schema / properties / ruleset
        Added value: +{
        +  "type": "string"
        +}
      • addedInput schema / properties / showBreadcrumbs
        Added value: +{
        +  "type": "boolean"
        +}
      • addedInput schema / properties / showInMenu
        Added value: +{
        +  "type": "boolean"
        +}
      • addedInput schema / properties / summary
        Added value: +{
        +  "description": "Short page summary; capped at 150 characters by imagine.",
        +  "maxLength": 150,
        +  "type": "string"
        +}
      • addedInput schema / properties / tags
        Added value: +{
        +  "description": "Tag list. Stored as a comma-separated `keywords` string on the wire.",
        +  "items": {
        +    "type": "string"
        +  },
        +  "type": "array"
        +}
      • addedInput schema / properties / template
        Added value: +{
        +  "type": "string"
        +}
      • addedInput schema / properties / vaultCharacterId
        Added value: +{
        +  "description": "Bind this page to a vault character (for character-shape world pages).",
        +  "type": "string"
        +}
      • addedInput schema / properties / visibility
        Added value: +{
        +  "description": "Page visibility. 'gm' pages exist only for the world's owner and contributors — every other viewer gets a 404 and the page is absent from lists, search, backlinks, and breadcrumbs. 'masked' pages participate in lists, tags, backlinks, and breadcrumbs but present maskName/maskSummary and an id-based URL to non-contributors; the real name, link, content, and aliases stay hidden until the page is flipped to public. Hidden pages are barred from the world menu. Default: 'public'.",
        +  "enum": [
        +    "public",
        +    "gm",
        +    "masked"
        +  ],
        +  "type": "string"
        +}
      • addedInput schema / properties / worldId
        Added value: +{
        +  "description": "World to add the page to.",
        +  "minLength": 1,
        +  "type": "string"
        +}
      • addedInput schema / required
        Added value: +[
        +  "worldId",
        +  "name"
        +]
    • Changedimagine_update_adventure27 fields changed
      • addedInput schema / $schema
        Added value: +"http://json-schema.org/draft-07/schema#"
      • addedInput schema / additionalProperties
        Added value: +{}
      • addedInput schema / properties / active
        Added value: +{
        +  "type": "boolean"
        +}
      • addedInput schema / properties / barImages
        Added value: +{
        +  "description": "GM-curated reference images displayed in a fixed bar across the adventure (maps, handouts, NPC portraits).",
        +  "items": {
        +    "additionalProperties": {},
        +    "properties": {
        +      "name": {
        +        "type": "string"
        +      },
        +      "url": {
        +        "description": "Image URL. Required by Mongoose; gateway leaves it optional so a missing url surfaces as a clean backend error.",
        +        "type": "string"
        +      }
        +    },
        +    "type": "object"
        +  },
        +  "type": "array"
        +}
      • addedInput schema / properties / baseUpdatedAt
        Added value: +{
        +  "description": "REQUIRED proof that you are working from the latest version: copy the `updatedAt` value verbatim from a FRESH read of this exact record (use the matching get tool first). Values from memory, from an earlier conversation, or guessed timestamps are rejected with OUT_OF_SYNC and nothing is written. After a successful update, the response carries the new `updatedAt` — use that for any follow-up write.",
        +  "minLength": 1,
        +  "type": "string"
        +}
      • addedInput schema / properties / companions
        Added value: +{
        +  "items": {
        +    "additionalProperties": {},
        +    "properties": {
        +      "name": {
        +        "type": "string"
        +      },
        +      "type": {
        +        "type": "string"
        +      },
        +      "vaultId": {
        +        "description": "Vault entity id (character/monster). Required by Mongoose.",
        +        "type": "string"
        +      }
        +    },
        +    "type": "object"
        +  },
        +  "type": "array"
        +}
      • addedInput schema / properties / contentWarnings
        Added value: +{
        +  "items": {
        +    "type": "string"
        +  },
        +  "type": "array"
        +}
      • addedInput schema / properties / description
        Added value: +{
        +  "description": "Full adventure description. Markdown supported.",
        +  "type": "string"
        +}
      • addedInput schema / properties / estimatedHours
        Added value: +{
        +  "type": "number"
        +}
      • addedInput schema / properties / id
        Added value: +{
        +  "description": "Adventure id.",
        +  "minLength": 1,
        +  "type": "string"
        +}
      • addedInput schema / properties / image
        Added value: +{
        +  "description": "Header image URL.",
        +  "type": "string"
        +}
      • addedInput schema / properties / imageCarousel
        Added value: +{
        +  "items": {
        +    "type": "string"
        +  },
        +  "type": "array"
        +}
      • addedInput schema / properties / keywords
        Added value: +{
        +  "description": "Comma-separated keyword string used by adventure-wide tag/search.",
        +  "type": "string"
        +}
      • addedInput schema / properties / level
        Added value: +{
        +  "additionalProperties": {},
        +  "description": "Recommended character level range. Each side optional; null means unset.",
        +  "properties": {
        +    "max": {
        +      "type": "number"
        +    },
        +    "min": {
        +      "type": "number"
        +    }
        +  },
        +  "type": "object"
        +}
      • addedInput schema / properties / link
        Added value: +{
        +  "description": "URL-safe slug. Lowercase letters, numbers, and hyphens. Imagine auto-suggests at create time when omitted.",
        +  "type": "string"
        +}
      • addedInput schema / properties / menuOrder
        Added value: +{
        +  "description": "Sort position among sibling parts of the same series parent. Send alone to reorder an existing part; omit when setting `parent` so the server appends to the end.",
        +  "maximum": 9007199254740991,
        +  "minimum": -9007199254740991,
        +  "type": "integer"
        +}
      • addedInput schema / properties / name
        Added value: +{
        +  "description": "Adventure name.",
        +  "minLength": 1,
        +  "type": "string"
        +}
      • addedInput schema / properties / parent
        Added value: +{
        +  "anyOf": [
        +    {
        +      "type": "string"
        +    },
        +    {
        +      "type": "null"
        +    }
        +  ],
        +  "description": "Series grouping: `_id` of the umbrella adventure this adventure is one part of. Depth is capped at one level — the parent cannot itself be a part, and an adventure that has parts cannot become a part (400 either way). The parent must be active and viewable by the caller (owner / contributor / public / stock), else 404. Pass null (or '') to clear. Setting a NEW parent without `menuOrder` appends the adventure to the end of the series."
        +}
      • addedInput schema / properties / partySize
        Added value: +{
        +  "additionalProperties": {},
        +  "description": "Recommended party size range.",
        +  "properties": {
        +    "max": {
        +      "type": "number"
        +    },
        +    "min": {
        +      "type": "number"
        +    }
        +  },
        +  "type": "object"
        +}
      • addedInput schema / properties / public
        Added value: +{
        +  "type": "boolean"
        +}
      • addedInput schema / properties / publisher
        Added value: +{
        +  "type": "string"
        +}
      • addedInput schema / properties / ruleset
        Added value: +{
        +  "description": "Ruleset code (e.g. '5th Edition', '5e24', 'PFRPG'). Required at create.",
        +  "type": "string"
        +}
      • addedInput schema / properties / status
        Added value: +{
        +  "enum": [
        +    "draft",
        +    "playtest",
        +    "published"
        +  ],
        +  "type": "string"
        +}
      • addedInput schema / properties / summary
        Added value: +{
        +  "description": "Short summary; capped at 150 characters by imagine.",
        +  "maxLength": 150,
        +  "type": "string"
        +}
      • addedInput schema / properties / version
        Added value: +{
        +  "type": "string"
        +}
      • addedInput schema / properties / world
        Added value: +{
        +  "description": "Optional World _id this adventure belongs to.",
        +  "minLength": 1,
        +  "type": "string"
        +}
      • addedInput schema / required
        Added value: +[
        +  "id",
        +  "baseUpdatedAt"
        +]
    • Changedimagine_update_adventure_page28 fields changed
      • addedInput schema / $schema
        Added value: +"http://json-schema.org/draft-07/schema#"
      • addedInput schema / additionalProperties
        Added value: +{}
      • addedInput schema / properties / active
        Added value: +{
        +  "type": "boolean"
        +}
      • addedInput schema / properties / aliases
        Added value: +{
        +  "items": {
        +    "type": "string"
        +  },
        +  "type": "array"
        +}
      • addedInput schema / properties / baseUpdatedAt
        Added value: +{
        +  "description": "REQUIRED proof that you are working from the latest version: copy the `updatedAt` value verbatim from a FRESH read of this exact record (use the matching get tool first). Values from memory, from an earlier conversation, or guessed timestamps are rejected with OUT_OF_SYNC and nothing is written. After a successful update, the response carries the new `updatedAt` — use that for any follow-up write.",
        +  "minLength": 1,
        +  "type": "string"
        +}
      • addedInput schema / properties / content
        Added value: +{
        +  "description": "Page body in markdown. Imagine renders this verbatim. WARNING: REPLACED wholesale on update; prefer imagine_replace_in_adventure_page for surgical edits.",
        +  "type": "string"
        +}
      • addedInput schema / properties / details
        Added value: +{
        +  "description": "Label/value list of arbitrary metadata pairs.",
        +  "items": {
        +    "additionalProperties": {},
        +    "properties": {
        +      "label": {
        +        "type": "string"
        +      },
        +      "value": {
        +        "type": "string"
        +      }
        +    },
        +    "type": "object"
        +  },
        +  "type": "array"
        +}
      • addedInput schema / properties / documentType
        Added value: +{
        +  "description": "Structural type. Drives shape-specific fields.",
        +  "enum": [
        +    "generic",
        +    "act",
        +    "scene",
        +    "location",
        +    "character",
        +    "handout",
        +    "lore",
        +    "appendix",
        +    "map"
        +  ],
        +  "type": "string"
        +}
      • addedInput schema / properties / duration
        Added value: +{
        +  "type": "string"
        +}
      • addedInput schema / properties / goal
        Added value: +{
        +  "type": "string"
        +}
      • addedInput schema / properties / id
        Added value: +{
        +  "description": "Adventure page id.",
        +  "minLength": 1,
        +  "type": "string"
        +}
      • addedInput schema / properties / image
        Added value: +{
        +  "type": "string"
        +}
      • addedInput schema / properties / link
        Added value: +{
        +  "description": "URL-safe slug. Lowercase letters, numbers, hyphens, slashes.",
        +  "type": "string"
        +}
      • addedInput schema / properties / locationKey
        Added value: +{
        +  "type": "string"
        +}
      • addedInput schema / properties / map
        Added value: +{
        +  "anyOf": [
        +    {
        +      "type": "string"
        +    },
        +    {
        +      "type": "null"
        +    }
        +  ],
        +  "description": "Location shape: Mongo `_id` of the Map this location belongs to. Pass null to clear."
        +}
      • addedInput schema / properties / mapPin
        Added value: +{
        +  "type": "string"
        +}
      • addedInput schema / properties / menuOrder
        Added value: +{
        +  "maximum": 9007199254740991,
        +  "minimum": -9007199254740991,
        +  "type": "integer"
        +}
      • addedInput schema / properties / name
        Added value: +{
        +  "description": "Page name.",
        +  "minLength": 1,
        +  "type": "string"
        +}
      • addedInput schema / properties / outboundLinks
        Added value: +{
        +  "description": "AdventurePage ids this page links to. Imagine recomputes this on save when missing; explicit values override.",
        +  "items": {
        +    "description": "Mongo `_id` reference (24-character hex string).",
        +    "minLength": 1,
        +    "type": "string"
        +  },
        +  "type": "array"
        +}
      • addedInput schema / properties / parentId
        Added value: +{
        +  "description": "Mongo `_id` of the parent page (for tree structure).",
        +  "type": "string"
        +}
      • addedInput schema / properties / relationships
        Added value: +{
        +  "description": "Sibling AdventurePage ids the page relates to.",
        +  "items": {
        +    "description": "Mongo `_id` reference (24-character hex string).",
        +    "minLength": 1,
        +    "type": "string"
        +  },
        +  "type": "array"
        +}
      • addedInput schema / properties / summary
        Added value: +{
        +  "description": "Short page summary. Max 150 characters (matches the AdventurePage Mongoose schema's maxlength). Sibling Adventure and WorldPage summaries share the same cap; legacy World summaries cap at 255 (cross-app convention).",
        +  "maxLength": 150,
        +  "type": "string"
        +}
      • addedInput schema / properties / tags
        Added value: +{
        +  "description": "Tag list. Imagine stores as a comma-separated `keywords` string.",
        +  "items": {
        +    "type": "string"
        +  },
        +  "type": "array"
        +}
      • addedInput schema / properties / template
        Added value: +{
        +  "description": "Template id when authored from a template.",
        +  "type": "string"
        +}
      • addedInput schema / properties / treasureRefs
        Added value: +{
        +  "description": "Treasure entries. Same shape as `vaultRefs`.",
        +  "items": {
        +    "additionalProperties": {},
        +    "properties": {
        +      "count": {
        +        "type": "number"
        +      },
        +      "name": {
        +        "type": "string"
        +      },
        +      "type": {
        +        "type": "string"
        +      },
        +      "vaultId": {
        +        "type": "string"
        +      }
        +    },
        +    "type": "object"
        +  },
        +  "type": "array"
        +}
      • addedInput schema / properties / vaultRefs
        Added value: +{
        +  "description": "Participants on the page. Each entry `{ vaultId?, type?, count?, name? }`.",
        +  "items": {
        +    "additionalProperties": {},
        +    "properties": {
        +      "count": {
        +        "type": "number"
        +      },
        +      "name": {
        +        "type": "string"
        +      },
        +      "type": {
        +        "type": "string"
        +      },
        +      "vaultId": {
        +        "type": "string"
        +      }
        +    },
        +    "type": "object"
        +  },
        +  "type": "array"
        +}
      • addedInput schema / properties / worldPageRefs
        Added value: +{
        +  "description": "Mongo `_id` list of referenced world pages.",
        +  "items": {
        +    "description": "Mongo `_id` reference (24-character hex string).",
        +    "minLength": 1,
        +    "type": "string"
        +  },
        +  "type": "array"
        +}
      • addedInput schema / required
        Added value: +[
        +  "id",
        +  "baseUpdatedAt"
        +]
    • Changedimagine_update_world20 fields changed
      • addedInput schema / $schema
        Added value: +"http://json-schema.org/draft-07/schema#"
      • addedInput schema / additionalProperties
        Added value: +{}
      • addedInput schema / properties / active
        Added value: +{
        +  "type": "boolean"
        +}
      • addedInput schema / properties / baseUpdatedAt
        Added value: +{
        +  "description": "REQUIRED proof that you are working from the latest version: copy the `updatedAt` value verbatim from a FRESH read of this exact record (use the matching get tool first). Values from memory, from an earlier conversation, or guessed timestamps are rejected with OUT_OF_SYNC and nothing is written. After a successful update, the response carries the new `updatedAt` — use that for any follow-up write.",
        +  "minLength": 1,
        +  "type": "string"
        +}
      • addedInput schema / properties / calendar
        Added value: +{
        +  "additionalProperties": {},
        +  "description": "Optional calendar definition (months[] + eras[]).",
        +  "properties": {
        +    "eras": {
        +      "items": {
        +        "additionalProperties": {},
        +        "properties": {
        +          "name": {
        +            "type": "string"
        +          },
        +          "order": {
        +            "type": "number"
        +          }
        +        },
        +        "type": "object"
        +      },
        +      "type": "array"
        +    },
        +    "months": {
        +      "items": {
        +        "additionalProperties": {},
        +        "properties": {
        +          "name": {
        +            "type": "string"
        +          },
        +          "order": {
        +            "type": "number"
        +          }
        +        },
        +        "type": "object"
        +      },
        +      "type": "array"
        +    }
        +  },
        +  "type": "object"
        +}
      • addedInput schema / properties / customDomain
        Added value: +{
        +  "description": "Optional custom domain pointing at the world's public site.",
        +  "type": "string"
        +}
      • addedInput schema / properties / description
        Added value: +{
        +  "description": "Full world description. Markdown supported.",
        +  "type": "string"
        +}
      • addedInput schema / properties / favicon
        Added value: +{
        +  "type": "string"
        +}
      • addedInput schema / properties / id
        Added value: +{
        +  "description": "Mongo `_id` of the world.",
        +  "minLength": 1,
        +  "type": "string"
        +}
      • addedInput schema / properties / image
        Added value: +{
        +  "type": "string"
        +}
      • addedInput schema / properties / imageCarousel
        Added value: +{
        +  "items": {
        +    "type": "string"
        +  },
        +  "type": "array"
        +}
      • addedInput schema / properties / isExampleWorld
        Added value: +{
        +  "type": "boolean"
        +}
      • addedInput schema / properties / keywords
        Added value: +{
        +  "type": "string"
        +}
      • addedInput schema / properties / link
        Added value: +{
        +  "description": "URL-safe slug for the world (lowercase letters, digits, hyphens). Imagine auto-suggests at create time when omitted.",
        +  "type": "string"
        +}
      • addedInput schema / properties / menu
        Added value: +{
        +  "description": "Site menu entries — label + optional link/pageId/order.",
        +  "items": {
        +    "additionalProperties": {},
        +    "properties": {
        +      "label": {
        +        "description": "Required by Mongoose.",
        +        "type": "string"
        +      },
        +      "link": {
        +        "type": "string"
        +      },
        +      "order": {
        +        "type": "number"
        +      },
        +      "pageId": {
        +        "description": "Mongo `_id` reference (24-character hex string).",
        +        "minLength": 1,
        +        "type": "string"
        +      }
        +    },
        +    "type": "object"
        +  },
        +  "type": "array"
        +}
      • addedInput schema / properties / name
        Added value: +{
        +  "description": "World name.",
        +  "minLength": 1,
        +  "type": "string"
        +}
      • addedInput schema / properties / public
        Added value: +{
        +  "description": "Whether the world is public. Only Premium, VIP, and admin accounts can change whether a world is public; the server refuses the change from anyone else. A new world is public unless set otherwise.",
        +  "type": "boolean"
        +}
      • addedInput schema / properties / showInvite
        Added value: +{
        +  "type": "boolean"
        +}
      • addedInput schema / properties / summary
        Added value: +{
        +  "description": "Short summary; capped at 255 characters. Cross-app convention (per dev-sites/AGENTS.md); the Mongoose World schema still accepts up to 500 as a legacy inconsistency being migrated, but new authoring should keep summaries under 255.",
        +  "maxLength": 255,
        +  "type": "string"
        +}
      • addedInput schema / required
        Added value: +[
        +  "id",
        +  "baseUpdatedAt"
        +]
    • Changedimagine_update_world_page32 fields changed
      • addedInput schema / $schema
        Added value: +"http://json-schema.org/draft-07/schema#"
      • addedInput schema / additionalProperties
        Added value: +{}
      • addedInput schema / properties / active
        Added value: +{
        +  "type": "boolean"
        +}
      • addedInput schema / properties / aliases
        Added value: +{
        +  "items": {
        +    "type": "string"
        +  },
        +  "type": "array"
        +}
      • addedInput schema / properties / baseUpdatedAt
        Added value: +{
        +  "description": "REQUIRED proof that you are working from the latest version: copy the `updatedAt` value verbatim from a FRESH read of this exact record (use the matching get tool first). Values from memory, from an earlier conversation, or guessed timestamps are rejected with OUT_OF_SYNC and nothing is written. After a successful update, the response carries the new `updatedAt` — use that for any follow-up write.",
        +  "minLength": 1,
        +  "type": "string"
        +}
      • addedInput schema / properties / content
        Added value: +{
        +  "description": "Page body in markdown. Imagine renders this verbatim. REPLACED wholesale on update.",
        +  "type": "string"
        +}
      • addedInput schema / properties / details
        Added value: +{
        +  "items": {
        +    "additionalProperties": {},
        +    "properties": {
        +      "label": {
        +        "type": "string"
        +      },
        +      "value": {
        +        "type": "string"
        +      }
        +    },
        +    "type": "object"
        +  },
        +  "type": "array"
        +}
      • addedInput schema / properties / documentType
        Added value: +{
        +  "enum": [
        +    "generic",
        +    "character",
        +    "location",
        +    "organization",
        +    "event",
        +    "lore",
        +    "religion",
        +    "cosmology"
        +  ],
        +  "type": "string"
        +}
      • addedInput schema / properties / eventDate
        Added value: +{
        +  "additionalProperties": {},
        +  "description": "Optional in-world event date for chronology-shape pages.",
        +  "properties": {
        +    "day": {
        +      "maximum": 9007199254740991,
        +      "minimum": -9007199254740991,
        +      "type": "integer"
        +    },
        +    "eraId": {
        +      "description": "Mongo `_id` reference (24-character hex string).",
        +      "minLength": 1,
        +      "type": "string"
        +    },
        +    "label": {
        +      "type": "string"
        +    },
        +    "monthId": {
        +      "description": "Mongo `_id` reference (24-character hex string).",
        +      "minLength": 1,
        +      "type": "string"
        +    },
        +    "year": {
        +      "maximum": 9007199254740991,
        +      "minimum": -9007199254740991,
        +      "type": "integer"
        +    }
        +  },
        +  "type": "object"
        +}
      • addedInput schema / properties / gmNotes
        Added value: +{
        +  "description": "GM-only notes attached to the page.",
        +  "type": "string"
        +}
      • addedInput schema / properties / id
        Added value: +{
        +  "description": "World page id.",
        +  "minLength": 1,
        +  "type": "string"
        +}
      • addedInput schema / properties / image
        Added value: +{
        +  "type": "string"
        +}
      • addedInput schema / properties / isWorldChild
        Added value: +{
        +  "type": "boolean"
        +}
      • addedInput schema / properties / link
        Added value: +{
        +  "description": "URL-safe slug. Lowercase letters, numbers, hyphens, slashes.",
        +  "type": "string"
        +}
      • addedInput schema / properties / maskName
        Added value: +{
        +  "description": "What non-contributors see instead of the page's name while visibility is 'masked'. Empty renders as 'Redacted'.",
        +  "type": "string"
        +}
      • addedInput schema / properties / maskSummary
        Added value: +{
        +  "description": "Optional teaser non-contributors see on the masked page; the real summary and content stay hidden. Max 255 characters.",
        +  "maxLength": 255,
        +  "type": "string"
        +}
      • addedInput schema / properties / menuLabel
        Added value: +{
        +  "type": "string"
        +}
      • addedInput schema / properties / menuOrder
        Added value: +{
        +  "maximum": 9007199254740991,
        +  "minimum": -9007199254740991,
        +  "type": "integer"
        +}
      • addedInput schema / properties / name
        Added value: +{
        +  "description": "Page name.",
        +  "minLength": 1,
        +  "type": "string"
        +}
      • addedInput schema / properties / outboundLinks
        Added value: +{
        +  "items": {
        +    "description": "Mongo `_id` reference (24-character hex string).",
        +    "minLength": 1,
        +    "type": "string"
        +  },
        +  "type": "array"
        +}
      • addedInput schema / properties / parentId
        Added value: +{
        +  "description": "Mongo `_id` of the parent world page (tree structure).",
        +  "type": "string"
        +}
      • addedInput schema / properties / playCampaignCharacters
        Added value: +{
        +  "items": {
        +    "additionalProperties": {},
        +    "properties": {
        +      "campaignId": {
        +        "type": "string"
        +      },
        +      "playCharacterId": {
        +        "description": "Mongo `_id` reference (24-character hex string).",
        +        "minLength": 1,
        +        "type": "string"
        +      }
        +    },
        +    "type": "object"
        +  },
        +  "type": "array"
        +}
      • addedInput schema / properties / relationships
        Added value: +{
        +  "items": {
        +    "description": "Mongo `_id` reference (24-character hex string).",
        +    "minLength": 1,
        +    "type": "string"
        +  },
        +  "type": "array"
        +}
      • addedInput schema / properties / ruleset
        Added value: +{
        +  "type": "string"
        +}
      • addedInput schema / properties / showBreadcrumbs
        Added value: +{
        +  "type": "boolean"
        +}
      • addedInput schema / properties / showInMenu
        Added value: +{
        +  "type": "boolean"
        +}
      • addedInput schema / properties / summary
        Added value: +{
        +  "description": "Short page summary; capped at 150 characters by imagine.",
        +  "maxLength": 150,
        +  "type": "string"
        +}
      • addedInput schema / properties / tags
        Added value: +{
        +  "description": "Tag list. Stored as a comma-separated `keywords` string on the wire.",
        +  "items": {
        +    "type": "string"
        +  },
        +  "type": "array"
        +}
      • addedInput schema / properties / template
        Added value: +{
        +  "type": "string"
        +}
      • addedInput schema / properties / vaultCharacterId
        Added value: +{
        +  "description": "Bind this page to a vault character (for character-shape world pages).",
        +  "type": "string"
        +}
      • addedInput schema / properties / visibility
        Added value: +{
        +  "description": "Page visibility. 'gm' pages exist only for the world's owner and contributors — every other viewer gets a 404 and the page is absent from lists, search, backlinks, and breadcrumbs. 'masked' pages participate in lists, tags, backlinks, and breadcrumbs but present maskName/maskSummary and an id-based URL to non-contributors; the real name, link, content, and aliases stay hidden until the page is flipped to public. Hidden pages are barred from the world menu. Default: 'public'.",
        +  "enum": [
        +    "public",
        +    "gm",
        +    "masked"
        +  ],
        +  "type": "string"
        +}
      • addedInput schema / required
        Added value: +[
        +  "id",
        +  "baseUpdatedAt"
        +]
    • Changedplay_create_campaign13 fields changed
      • addedInput schema / $schema
        Added value: +"http://json-schema.org/draft-07/schema#"
      • addedInput schema / additionalProperties
        Added value: +{}
      • addedInput schema / properties / active
        Added value: +{
        +  "type": "boolean"
        +}
      • addedInput schema / properties / description
        Added value: +{
        +  "description": "Full campaign description. Markdown supported.",
        +  "type": "string"
        +}
      • addedInput schema / properties / hideSections
        Added value: +{
        +  "additionalProperties": {},
        +  "properties": {
        +    "characters": {
        +      "type": "boolean"
        +    },
        +    "logistics": {
        +      "type": "boolean"
        +    },
        +    "players": {
        +      "type": "boolean"
        +    },
        +    "rules": {
        +      "type": "boolean"
        +    },
        +    "safetyTools": {
        +      "type": "boolean"
        +    },
        +    "sessionZero": {
        +      "type": "boolean"
        +    },
        +    "sessions": {
        +      "type": "boolean"
        +    }
        +  },
        +  "type": "object"
        +}
      • addedInput schema / properties / image
        Added value: +{
        +  "description": "Image URL. Stored as a plain string.",
        +  "type": "string"
        +}
      • addedInput schema / properties / name
        Added value: +{
        +  "description": "Campaign name. Required.",
        +  "minLength": 1,
        +  "type": "string"
        +}
      • addedInput schema / properties / public
        Added value: +{
        +  "description": "Whether non-members can see the campaign.",
        +  "type": "boolean"
        +}
      • addedInput schema / properties / ruleset
        Added value: +{
        +  "description": "Ruleset code (e.g. '5th Edition', '5e24', 'PFRPG', 'Savage Worlds'). Becomes the campaign's first leg. Play enforces required on the backend; the gateway lets it be omitted so the LLM gets a clean backend error if it forgets.",
        +  "enum": [
        +    "5th Edition",
        +    "5e24",
        +    "PFRPG",
        +    "PFRPG2",
        +    "PF Playtest",
        +    "Savage Worlds",
        +    "Savage Embers",
        +    "Solarian Conflict",
        +    "Embers RPG",
        +    "Universal",
        +    "Fate Core",
        +    "Fate Accelerated"
        +  ],
        +  "type": "string"
        +}
      • addedInput schema / properties / sessions
        Added value: +{
        +  "items": {
        +    "description": "Mongo `_id` reference (24-character hex string).",
        +    "minLength": 1,
        +    "type": "string"
        +  },
        +  "type": "array"
        +}
      • addedInput schema / properties / summary
        Added value: +{
        +  "description": "Short campaign summary. Max 150 characters.",
        +  "maxLength": 150,
        +  "type": "string"
        +}
      • addedInput schema / properties / xCardEnabled
        Added value: +{
        +  "type": "boolean"
        +}
      • addedInput schema / required
        Added value: +[
        +  "name"
        +]
    • Changedplay_create_move11 fields changed
      • addedInput schema / $schema
        Added value: +"http://json-schema.org/draft-07/schema#"
      • addedInput schema / additionalProperties
        Added value: +{}
      • addedInput schema / properties / campaignId
        Added value: +{
        +  "description": "Campaign the move belongs to. Required. Caller must be the campaign owner or an accepted gamemaster.",
        +  "minLength": 1,
        +  "type": "string"
        +}
      • addedInput schema / properties / date
        Added value: +{
        +  "description": "Move date in `dd/mm/yy` format. Defaults to today on create. Play parses this server-side on both create and update.",
        +  "pattern": "^(\\d{1,2})\\/(\\d{1,2})\\/(\\d{2})$",
        +  "type": "string"
        +}
      • addedInput schema / properties / description
        Added value: +{
        +  "description": "The collated round: GM narration, player contributions, rolls. Markdown supported.",
        +  "type": "string"
        +}
      • addedInput schema / properties / name
        Added value: +{
        +  "description": "Move name / title (e.g. 'Move 185', 'Interlude 12'). Defaults to 'Move <number>' when omitted on create.",
        +  "minLength": 1,
        +  "type": "string"
        +}
      • addedInput schema / properties / number
        Added value: +{
        +  "description": "Game label number. Non-unique (parallel scenes share one). Defaults to the campaign's high-water + 1 on create. Display position is `order`, not this.",
        +  "exclusiveMinimum": 0,
        +  "maximum": 9007199254740991,
        +  "type": "integer"
        +}
      • addedInput schema / properties / parentId
        Added value: +{
        +  "anyOf": [
        +    {
        +      "minLength": 1,
        +      "type": "string"
        +    },
        +    {
        +      "type": "null"
        +    }
        +  ],
        +  "description": "Parent move, making this a child scene (split party). Same campaign only, one level deep (a child cannot be a parent; a move with children cannot become a child). Children render on the parent's page, stay out of the feed and chapter lists, and cannot carry a sessionId. Pass null to detach back into the feed."
        +}
      • addedInput schema / properties / playerIds
        Added value: +{
        +  "description": "Visibility restriction: user ids from the campaign's player roster. Empty/omitted = visible to every campaign participant. When set, the move is invisible to players not listed (dropped from lists, 404 on read); the GM always sees it. Pass [] on update to reopen the move to everyone.",
        +  "items": {
        +    "minLength": 1,
        +    "type": "string"
        +  },
        +  "type": "array"
        +}
      • addedInput schema / properties / sessionId
        Added value: +{
        +  "anyOf": [
        +    {
        +      "minLength": 1,
        +      "type": "string"
        +    },
        +    {
        +      "type": "null"
        +    }
        +  ],
        +  "description": "Chapter session to group this move under. Must belong to the same campaign. Pass null to detach the move back to the unchaptered feed."
        +}
      • addedInput schema / required
        Added value: +[
        +  "campaignId"
        +]
    • Changedplay_create_page13 fields changed
      • addedInput schema / $schema
        Added value: +"http://json-schema.org/draft-07/schema#"
      • addedInput schema / additionalProperties
        Added value: +{}
      • addedInput schema / properties / active
        Added value: +{
        +  "type": "boolean"
        +}
      • addedInput schema / properties / description
        Added value: +{
        +  "description": "Markdown body.",
        +  "type": "string"
        +}
      • addedInput schema / properties / documentType
        Added value: +{
        +  "description": "What kind of page this is. Defaults to 'generic'. Use 'player-recap' for a session recap.",
        +  "enum": [
        +    "generic",
        +    "player-recap",
        +    "dm-notes",
        +    "player-notes",
        +    "campaign-logistics"
        +  ],
        +  "type": "string"
        +}
      • addedInput schema / properties / keywords
        Added value: +{
        +  "description": "Comma-separated keyword string.",
        +  "type": "string"
        +}
      • addedInput schema / properties / link
        Added value: +{
        +  "description": "URL-safe slug. Lowercase letters, numbers, and hyphens only.",
        +  "pattern": "^[a-z0-9-]+$",
        +  "type": "string"
        +}
      • addedInput schema / properties / name
        Added value: +{
        +  "description": "Page name / title. Required.",
        +  "minLength": 1,
        +  "type": "string"
        +}
      • addedInput schema / properties / promptId
        Added value: +{
        +  "description": "Mongo `_id` reference (24-character hex string).",
        +  "minLength": 1,
        +  "type": "string"
        +}
      • addedInput schema / properties / public
        Added value: +{
        +  "type": "boolean"
        +}
      • addedInput schema / properties / ref
        Added value: +{
        +  "additionalProperties": {},
        +  "description": "What the page is attached to. Required for character notes; optional for free-form pages. Allowed on update too (Mongoose has no immutability constraint), though re-anchoring a page is unusual.",
        +  "properties": {
        +    "refId": {
        +      "minLength": 1,
        +      "type": "string"
        +    },
        +    "refType": {
        +      "enum": [
        +        "campaign",
        +        "session",
        +        "character"
        +      ],
        +      "type": "string"
        +    }
        +  },
        +  "type": "object"
        +}
      • addedInput schema / properties / summary
        Added value: +{
        +  "description": "Short page summary. Max 255 characters.",
        +  "maxLength": 255,
        +  "type": "string"
        +}
      • addedInput schema / required
        Added value: +[
        +  "name"
        +]
    • Changedplay_create_session13 fields changed
      • addedInput schema / $schema
        Added value: +"http://json-schema.org/draft-07/schema#"
      • addedInput schema / additionalProperties
        Added value: +{}
      • addedInput schema / properties / battlemaps
        Added value: +{
        +  "items": {
        +    "additionalProperties": {},
        +    "properties": {
        +      "_id": {
        +        "description": "Mongo `_id` reference (24-character hex string).",
        +        "minLength": 1,
        +        "type": "string"
        +      },
        +      "visibleToPlayers": {
        +        "type": "boolean"
        +      }
        +    },
        +    "type": "object"
        +  },
        +  "type": "array"
        +}
      • addedInput schema / properties / campaignId
        Added value: +{
        +  "description": "Campaign the session belongs to. Required.",
        +  "minLength": 1,
        +  "type": "string"
        +}
      • addedInput schema / properties / characters
        Added value: +{
        +  "items": {
        +    "description": "Mongo `_id` reference (24-character hex string).",
        +    "minLength": 1,
        +    "type": "string"
        +  },
        +  "type": "array"
        +}
      • addedInput schema / properties / date
        Added value: +{
        +  "description": "Planned or actual session date in `dd/mm/yy` format. Required.",
        +  "pattern": "^(\\d{1,2})\\/(\\d{1,2})\\/(\\d{2})$",
        +  "type": "string"
        +}
      • addedInput schema / properties / description
        Added value: +{
        +  "description": "Session body / notes / recap. Markdown supported.",
        +  "type": "string"
        +}
      • addedInput schema / properties / image
        Added value: +{
        +  "type": "string"
        +}
      • addedInput schema / properties / name
        Added value: +{
        +  "description": "Session name / title.",
        +  "minLength": 1,
        +  "type": "string"
        +}
      • addedInput schema / properties / sessionImages
        Added value: +{
        +  "items": {
        +    "additionalProperties": {},
        +    "properties": {
        +      "name": {
        +        "type": "string"
        +      },
        +      "url": {
        +        "type": "string"
        +      },
        +      "visibleToPlayers": {
        +        "type": "boolean"
        +      }
        +    },
        +    "type": "object"
        +  },
        +  "type": "array"
        +}
      • addedInput schema / properties / status
        Added value: +{
        +  "enum": [
        +    "pending",
        +    "active",
        +    "completed",
        +    "cancelled"
        +  ],
        +  "type": "string"
        +}
      • addedInput schema / properties / summary
        Added value: +{
        +  "description": "Short session summary. Max 150 characters.",
        +  "maxLength": 150,
        +  "type": "string"
        +}
      • addedInput schema / required
        Added value: +[
        +  "campaignId",
        +  "date"
        +]
    • Changedplay_update_campaign14 fields changed
      • addedInput schema / $schema
        Added value: +"http://json-schema.org/draft-07/schema#"
      • addedInput schema / additionalProperties
        Added value: +{}
      • addedInput schema / properties / active
        Added value: +{
        +  "type": "boolean"
        +}
      • addedInput schema / properties / baseUpdatedAt
        Added value: +{
        +  "description": "REQUIRED proof that you are working from the latest version: copy the `updatedAt` value verbatim from a FRESH read of this exact record (use the matching get tool first). Values from memory, from an earlier conversation, or guessed timestamps are rejected with OUT_OF_SYNC and nothing is written. After a successful update, the response carries the new `updatedAt` — use that for any follow-up write.",
        +  "minLength": 1,
        +  "type": "string"
        +}
      • addedInput schema / properties / description
        Added value: +{
        +  "description": "Full campaign description. Markdown supported.",
        +  "type": "string"
        +}
      • addedInput schema / properties / hideSections
        Added value: +{
        +  "additionalProperties": {},
        +  "properties": {
        +    "characters": {
        +      "type": "boolean"
        +    },
        +    "logistics": {
        +      "type": "boolean"
        +    },
        +    "players": {
        +      "type": "boolean"
        +    },
        +    "rules": {
        +      "type": "boolean"
        +    },
        +    "safetyTools": {
        +      "type": "boolean"
        +    },
        +    "sessionZero": {
        +      "type": "boolean"
        +    },
        +    "sessions": {
        +      "type": "boolean"
        +    }
        +  },
        +  "type": "object"
        +}
      • addedInput schema / properties / id
        Added value: +{
        +  "description": "Mongo `_id` of the campaign.",
        +  "minLength": 1,
        +  "type": "string"
        +}
      • addedInput schema / properties / image
        Added value: +{
        +  "description": "Image URL. Stored as a plain string.",
        +  "type": "string"
        +}
      • addedInput schema / properties / name
        Added value: +{
        +  "description": "Campaign name.",
        +  "minLength": 1,
        +  "type": "string"
        +}
      • addedInput schema / properties / public
        Added value: +{
        +  "description": "Whether non-members can see the campaign.",
        +  "type": "boolean"
        +}
      • addedInput schema / properties / sessions
        Added value: +{
        +  "items": {
        +    "description": "Mongo `_id` reference (24-character hex string).",
        +    "minLength": 1,
        +    "type": "string"
        +  },
        +  "type": "array"
        +}
      • addedInput schema / properties / summary
        Added value: +{
        +  "description": "Short campaign summary. Max 150 characters.",
        +  "maxLength": 150,
        +  "type": "string"
        +}
      • addedInput schema / properties / xCardEnabled
        Added value: +{
        +  "type": "boolean"
        +}
      • addedInput schema / required
        Added value: +[
        +  "id",
        +  "baseUpdatedAt"
        +]
    • Changedplay_update_character_note8 fields changed
      • addedInput schema / $schema
        Added value: +"http://json-schema.org/draft-07/schema#"
      • addedInput schema / additionalProperties
        Added value: +{}
      • addedInput schema / properties / baseUpdatedAt
        Added value: +{
        +  "description": "REQUIRED proof that you are working from the latest version: copy the `updatedAt` value verbatim from a FRESH read of this exact record (use the matching get tool first). Values from memory, from an earlier conversation, or guessed timestamps are rejected with OUT_OF_SYNC and nothing is written. After a successful update, the response carries the new `updatedAt` — use that for any follow-up write.",
        +  "minLength": 1,
        +  "type": "string"
        +}
      • addedInput schema / properties / characterId
        Added value: +{
        +  "description": "Mongo `_id` of the play character (NOT the vault character id).",
        +  "minLength": 1,
        +  "type": "string"
        +}
      • addedInput schema / properties / description
        Added value: +{
        +  "description": "Note body markdown. PUT semantics: replaces the existing body.",
        +  "type": "string"
        +}
      • addedInput schema / properties / documentType
        Added value: +{
        +  "description": "Which note to update: 'dm-notes' or 'player-notes'.",
        +  "enum": [
        +    "dm-notes",
        +    "player-notes"
        +  ],
        +  "type": "string"
        +}
      • addedInput schema / properties / name
        Added value: +{
        +  "description": "Optional new name for the note.",
        +  "minLength": 1,
        +  "type": "string"
        +}
      • addedInput schema / required
        Added value: +[
        +  "characterId",
        +  "baseUpdatedAt",
        +  "documentType",
        +  "description"
        +]
    • Changedplay_update_move13 fields changed
      • addedInput schema / $schema
        Added value: +"http://json-schema.org/draft-07/schema#"
      • addedInput schema / additionalProperties
        Added value: +{}
      • addedInput schema / properties / baseUpdatedAt
        Added value: +{
        +  "description": "REQUIRED proof that you are working from the latest version: copy the `updatedAt` value verbatim from a FRESH read of this exact record (use the matching get tool first). Values from memory, from an earlier conversation, or guessed timestamps are rejected with OUT_OF_SYNC and nothing is written. After a successful update, the response carries the new `updatedAt` — use that for any follow-up write.",
        +  "minLength": 1,
        +  "type": "string"
        +}
      • addedInput schema / properties / date
        Added value: +{
        +  "description": "Move date in `dd/mm/yy` format. Defaults to today on create. Play parses this server-side on both create and update.",
        +  "pattern": "^(\\d{1,2})\\/(\\d{1,2})\\/(\\d{2})$",
        +  "type": "string"
        +}
      • addedInput schema / properties / description
        Added value: +{
        +  "description": "The collated round: GM narration, player contributions, rolls. Markdown supported.",
        +  "type": "string"
        +}
      • addedInput schema / properties / id
        Added value: +{
        +  "description": "Mongo `_id` of the move to update.",
        +  "minLength": 1,
        +  "type": "string"
        +}
      • addedInput schema / properties / name
        Added value: +{
        +  "description": "Move name / title (e.g. 'Move 185', 'Interlude 12'). Defaults to 'Move <number>' when omitted on create.",
        +  "minLength": 1,
        +  "type": "string"
        +}
      • addedInput schema / properties / number
        Added value: +{
        +  "description": "Game label number. Non-unique (parallel scenes share one). Defaults to the campaign's high-water + 1 on create. Display position is `order`, not this.",
        +  "exclusiveMinimum": 0,
        +  "maximum": 9007199254740991,
        +  "type": "integer"
        +}
      • addedInput schema / properties / order
        Added value: +{
        +  "description": "Shelf position within the campaign (the feed's only sort key; GM drag-reordering rewrites it). Positive integer.",
        +  "exclusiveMinimum": 0,
        +  "maximum": 9007199254740991,
        +  "type": "integer"
        +}
      • addedInput schema / properties / parentId
        Added value: +{
        +  "anyOf": [
        +    {
        +      "minLength": 1,
        +      "type": "string"
        +    },
        +    {
        +      "type": "null"
        +    }
        +  ],
        +  "description": "Parent move, making this a child scene (split party). Same campaign only, one level deep (a child cannot be a parent; a move with children cannot become a child). Children render on the parent's page, stay out of the feed and chapter lists, and cannot carry a sessionId. Pass null to detach back into the feed."
        +}
      • addedInput schema / properties / playerIds
        Added value: +{
        +  "description": "Visibility restriction: user ids from the campaign's player roster. Empty/omitted = visible to every campaign participant. When set, the move is invisible to players not listed (dropped from lists, 404 on read); the GM always sees it. Pass [] on update to reopen the move to everyone.",
        +  "items": {
        +    "minLength": 1,
        +    "type": "string"
        +  },
        +  "type": "array"
        +}
      • addedInput schema / properties / sessionId
        Added value: +{
        +  "anyOf": [
        +    {
        +      "minLength": 1,
        +      "type": "string"
        +    },
        +    {
        +      "type": "null"
        +    }
        +  ],
        +  "description": "Chapter session to group this move under. Must belong to the same campaign. Pass null to detach the move back to the unchaptered feed."
        +}
      • addedInput schema / required
        Added value: +[
        +  "id",
        +  "baseUpdatedAt"
        +]
    • Changedplay_update_page15 fields changed
      • addedInput schema / $schema
        Added value: +"http://json-schema.org/draft-07/schema#"
      • addedInput schema / additionalProperties
        Added value: +{}
      • addedInput schema / properties / active
        Added value: +{
        +  "type": "boolean"
        +}
      • addedInput schema / properties / baseUpdatedAt
        Added value: +{
        +  "description": "REQUIRED proof that you are working from the latest version: copy the `updatedAt` value verbatim from a FRESH read of this exact record (use the matching get tool first). Values from memory, from an earlier conversation, or guessed timestamps are rejected with OUT_OF_SYNC and nothing is written. After a successful update, the response carries the new `updatedAt` — use that for any follow-up write.",
        +  "minLength": 1,
        +  "type": "string"
        +}
      • addedInput schema / properties / description
        Added value: +{
        +  "description": "Markdown body.",
        +  "type": "string"
        +}
      • addedInput schema / properties / documentType
        Added value: +{
        +  "description": "What kind of page this is. Defaults to 'generic'. Use 'player-recap' for a session recap.",
        +  "enum": [
        +    "generic",
        +    "player-recap",
        +    "dm-notes",
        +    "player-notes",
        +    "campaign-logistics"
        +  ],
        +  "type": "string"
        +}
      • addedInput schema / properties / id
        Added value: +{
        +  "description": "Mongo `_id` of the page to update.",
        +  "minLength": 1,
        +  "type": "string"
        +}
      • addedInput schema / properties / keywords
        Added value: +{
        +  "description": "Comma-separated keyword string.",
        +  "type": "string"
        +}
      • addedInput schema / properties / link
        Added value: +{
        +  "description": "URL-safe slug. Lowercase letters, numbers, and hyphens only.",
        +  "pattern": "^[a-z0-9-]+$",
        +  "type": "string"
        +}
      • addedInput schema / properties / name
        Added value: +{
        +  "description": "Page name / title.",
        +  "minLength": 1,
        +  "type": "string"
        +}
      • addedInput schema / properties / promptId
        Added value: +{
        +  "description": "Mongo `_id` reference (24-character hex string).",
        +  "minLength": 1,
        +  "type": "string"
        +}
      • addedInput schema / properties / public
        Added value: +{
        +  "type": "boolean"
        +}
      • addedInput schema / properties / ref
        Added value: +{
        +  "additionalProperties": {},
        +  "description": "What the page is attached to. Required for character notes; optional for free-form pages. Allowed on update too (Mongoose has no immutability constraint), though re-anchoring a page is unusual.",
        +  "properties": {
        +    "refId": {
        +      "minLength": 1,
        +      "type": "string"
        +    },
        +    "refType": {
        +      "enum": [
        +        "campaign",
        +        "session",
        +        "character"
        +      ],
        +      "type": "string"
        +    }
        +  },
        +  "type": "object"
        +}
      • addedInput schema / properties / summary
        Added value: +{
        +  "description": "Short page summary. Max 255 characters.",
        +  "maxLength": 255,
        +  "type": "string"
        +}
      • addedInput schema / required
        Added value: +[
        +  "id",
        +  "baseUpdatedAt"
        +]
    • Changedplay_update_session18 fields changed
      • addedInput schema / $schema
        Added value: +"http://json-schema.org/draft-07/schema#"
      • addedInput schema / additionalProperties
        Added value: +{}
      • addedInput schema / properties / baseUpdatedAt
        Added value: +{
        +  "description": "REQUIRED proof that you are working from the latest version: copy the `updatedAt` value verbatim from a FRESH read of this exact record (use the matching get tool first). Values from memory, from an earlier conversation, or guessed timestamps are rejected with OUT_OF_SYNC and nothing is written. After a successful update, the response carries the new `updatedAt` — use that for any follow-up write.",
        +  "minLength": 1,
        +  "type": "string"
        +}
      • addedInput schema / properties / battlemaps
        Added value: +{
        +  "items": {
        +    "additionalProperties": {},
        +    "properties": {
        +      "_id": {
        +        "description": "Mongo `_id` reference (24-character hex string).",
        +        "minLength": 1,
        +        "type": "string"
        +      },
        +      "visibleToPlayers": {
        +        "type": "boolean"
        +      }
        +    },
        +    "type": "object"
        +  },
        +  "type": "array"
        +}
      • addedInput schema / properties / characters
        Added value: +{
        +  "items": {
        +    "description": "Mongo `_id` reference (24-character hex string).",
        +    "minLength": 1,
        +    "type": "string"
        +  },
        +  "type": "array"
        +}
      • addedInput schema / properties / date
        Added value: +{
        +  "description": "Session date in `dd/mm/yy` format.",
        +  "pattern": "^(\\d{1,2})\\/(\\d{1,2})\\/(\\d{2})$",
        +  "type": "string"
        +}
      • addedInput schema / properties / dateDay
        Added value: +{
        +  "maximum": 31,
        +  "minimum": 1,
        +  "type": "integer"
        +}
      • addedInput schema / properties / dateMonth
        Added value: +{
        +  "maximum": 12,
        +  "minimum": 1,
        +  "type": "integer"
        +}
      • addedInput schema / properties / dateYear
        Added value: +{
        +  "maximum": 9007199254740991,
        +  "minimum": -9007199254740991,
        +  "type": "integer"
        +}
      • addedInput schema / properties / description
        Added value: +{
        +  "description": "Session body / notes / recap. Markdown supported.",
        +  "type": "string"
        +}
      • addedInput schema / properties / id
        Added value: +{
        +  "description": "Mongo `_id` of the session to update.",
        +  "minLength": 1,
        +  "type": "string"
        +}
      • addedInput schema / properties / image
        Added value: +{
        +  "type": "string"
        +}
      • addedInput schema / properties / imagineAdventureId
        Added value: +{
        +  "anyOf": [
        +    {
        +      "minLength": 1,
        +      "type": "string"
        +    },
        +    {
        +      "type": "null"
        +    }
        +  ],
        +  "description": "Imagine adventure this session is part of. Must be one of the ids in the campaign's `imagineAdventures` list (see play_get_campaign); adventures are linked to the campaign with imagine_link_adventure_to_campaign. Pass null to untag the session. Omit to leave unchanged."
        +}
      • addedInput schema / properties / name
        Added value: +{
        +  "description": "Session name / title.",
        +  "minLength": 1,
        +  "type": "string"
        +}
      • addedInput schema / properties / sessionImages
        Added value: +{
        +  "items": {
        +    "additionalProperties": {},
        +    "properties": {
        +      "name": {
        +        "type": "string"
        +      },
        +      "url": {
        +        "type": "string"
        +      },
        +      "visibleToPlayers": {
        +        "type": "boolean"
        +      }
        +    },
        +    "type": "object"
        +  },
        +  "type": "array"
        +}
      • addedInput schema / properties / status
        Added value: +{
        +  "enum": [
        +    "pending",
        +    "active",
        +    "completed",
        +    "cancelled"
        +  ],
        +  "type": "string"
        +}
      • addedInput schema / properties / summary
        Added value: +{
        +  "description": "Short session summary. Max 150 characters.",
        +  "maxLength": 150,
        +  "type": "string"
        +}
      • addedInput schema / required
        Added value: +[
        +  "id",
        +  "baseUpdatedAt"
        +]
    • Changedvault_build_pc36 fields changed
      • addedInput schema / $schema
        Added value: +"http://json-schema.org/draft-07/schema#"
      • addedInput schema / additionalProperties
        Added value: +{}
      • addedInput schema / properties / abilityBumpPicks
        Added value: +{
        +  "additionalProperties": {
        +    "additionalProperties": {},
        +    "properties": {
        +      "lines": {
        +        "items": {
        +          "items": {
        +            "type": "string"
        +          },
        +          "type": "array"
        +        },
        +        "type": "array"
        +      },
        +      "option": {
        +        "maximum": 9007199254740991,
        +        "minimum": 0,
        +        "type": "integer"
        +      }
        +    },
        +    "type": "object"
        +  },
        +  "description": "Ability-score-increase picks for any applied rule carrying an `abilityScoreBump` (a feat / ability that raises a score by your choice — e.g. an ASI). Key is the granting rule `_id`; value is `{ option, lines }`: `option` is the 0-based index of the chosen alternative in that bump's `options` (the player picks exactly ONE — the OR), and `lines` is parallel to that option's `lines`, each entry the lowercase ability names assigned to that line (the AND). Each line needs exactly its `count` distinct abilities drawn from its `eligible` pool (empty = any of the six), none exceeding its `max`. The build bakes the increases onto the ability scores before HP, so a Constitution increase feeds level-1 HP. A `repeatable` feat filling the background slot keys `bg:<featId>` instead of `<featId>`.",
        +  "propertyNames": {
        +    "type": "string"
        +  },
        +  "type": "object"
        +}
      • addedInput schema / properties / abilityChoices
        Added value: +{
        +  "additionalProperties": {
        +    "items": {
        +      "type": "string"
        +    },
        +    "type": "array"
        +  },
        +  "description": "Picks for a class ability's `choice` (ruleChoice). Key is the ability rule `_id`; value is exactly `choice.count` picked option `_id`s from `choice.options`. Each option carries a `type`. When a picked option carries its OWN sub-choices (any type — an Ability like a Cleric's Divine Order → Thaumaturge, or a Feat granted 'of your choice'), supply them in `proficiencyChoicePicks` / `spellChoicePicks` / `spellListChoicePicks` / `preparedSpellPicks` keyed by the picked option's `_id`, just like the background feat.",
        +  "propertyNames": {
        +    "type": "string"
        +  },
        +  "type": "object"
        +}
      • addedInput schema / properties / abilityScoreAssignments
        Added value: +{
        +  "description": "Final ability scores by key, all six required. Must satisfy the chosen `abilityScoreMethod`: standard-array uses [15,14,13,12,10,8] in any order; point-buy each in 8..15 within the budget; class-array is taken from the class's defaultAbilityScores (still send the six values you intend).",
        +  "properties": {
        +    "charisma": {
        +      "maximum": 9007199254740991,
        +      "minimum": -9007199254740991,
        +      "type": "integer"
        +    },
        +    "constitution": {
        +      "maximum": 9007199254740991,
        +      "minimum": -9007199254740991,
        +      "type": "integer"
        +    },
        +    "dexterity": {
        +      "maximum": 9007199254740991,
        +      "minimum": -9007199254740991,
        +      "type": "integer"
        +    },
        +    "intelligence": {
        +      "maximum": 9007199254740991,
        +      "minimum": -9007199254740991,
        +      "type": "integer"
        +    },
        +    "strength": {
        +      "maximum": 9007199254740991,
        +      "minimum": -9007199254740991,
        +      "type": "integer"
        +    },
        +    "wisdom": {
        +      "maximum": 9007199254740991,
        +      "minimum": -9007199254740991,
        +      "type": "integer"
        +    }
        +  },
        +  "required": [
        +    "strength",
        +    "dexterity",
        +    "constitution",
        +    "intelligence",
        +    "wisdom",
        +    "charisma"
        +  ],
        +  "type": "object"
        +}
      • addedInput schema / properties / abilityScoreMethod
        Added value: +{
        +  "description": "How ability scores were chosen. See `constants.abilityScoreMethods` for the array / point-buy budget / costs.",
        +  "enum": [
        +    "standard-array",
        +    "point-buy",
        +    "class-array"
        +  ],
        +  "type": "string"
        +}
      • addedInput schema / properties / abilityScorePointBudget
        Added value: +{
        +  "description": "Point-buy budget override. Defaults to 27 (5e24). Only used for `abilityScoreMethod: 'point-buy'`.",
        +  "maximum": 9007199254740991,
        +  "minimum": 0,
        +  "type": "integer"
        +}
      • addedInput schema / properties / alignment
        Added value: +{
        +  "enum": [
        +    "Lawful Good",
        +    "Neutral Good",
        +    "Chaotic Good",
        +    "Lawful Neutral",
        +    "Neutral",
        +    "Chaotic Neutral",
        +    "Lawful Evil",
        +    "Neutral Evil",
        +    "Chaotic Evil"
        +  ],
        +  "type": "string"
        +}
      • addedInput schema / properties / appearances
        Added value: +{
        +  "description": "Appearance roster — `[{ url }]`. The portrait (`image`) is typically the default appearance.",
        +  "items": {
        +    "additionalProperties": {},
        +    "properties": {
        +      "url": {
        +        "description": "Image URL hosted on Embers Images (or any addressable HTTPS URL).",
        +        "type": "string"
        +      }
        +    },
        +    "type": "object"
        +  },
        +  "type": "array"
        +}
      • addedInput schema / properties / backgroundBumpAssignments
        Added value: +{
        +  "additionalProperties": {},
        +  "description": "Background ability-score bump per key. 'twoOne' mode: one ability +2 and a different one +1. 'oneOneOne' mode: three different abilities +1. Keys not bumped are omitted or 0. Only the background's `abilityScores` keys are eligible.",
        +  "properties": {
        +    "charisma": {
        +      "maximum": 2,
        +      "minimum": 0,
        +      "type": "integer"
        +    },
        +    "constitution": {
        +      "maximum": 2,
        +      "minimum": 0,
        +      "type": "integer"
        +    },
        +    "dexterity": {
        +      "maximum": 2,
        +      "minimum": 0,
        +      "type": "integer"
        +    },
        +    "intelligence": {
        +      "maximum": 2,
        +      "minimum": 0,
        +      "type": "integer"
        +    },
        +    "strength": {
        +      "maximum": 2,
        +      "minimum": 0,
        +      "type": "integer"
        +    },
        +    "wisdom": {
        +      "maximum": 2,
        +      "minimum": 0,
        +      "type": "integer"
        +    }
        +  },
        +  "type": "object"
        +}
      • addedInput schema / properties / backgroundBumpMode
        Added value: +{
        +  "description": "Required when the background grants an ability bump. 'twoOne' = +2/+1; 'oneOneOne' = +1/+1/+1.",
        +  "enum": [
        +    "twoOne",
        +    "oneOneOne"
        +  ],
        +  "type": "string"
        +}
      • addedInput schema / properties / backgroundFeatChoices
        Added value: +{
        +  "additionalProperties": {
        +    "items": {
        +      "type": "string"
        +    },
        +    "type": "array"
        +  },
        +  "description": "Picks for the background feat's `choice` (ruleChoice) AND for any choice carried by the feat's granted abilities. Key is the feat `_id` (its own choice) or the granted ability's `_id` (that ability's choice); value is the picked rule `_id`s.",
        +  "propertyNames": {
        +    "type": "string"
        +  },
        +  "type": "object"
        +}
      • addedInput schema / properties / backgroundFeatRuleId
        Added value: +{
        +  "description": "The background's Origin feat. REQUIRED when `background.featOpen` is true (an open slot — the build rejects the draft without it); optional on a fixed-feat background, where supplying it swaps the authored default. Must be an Origin-category feat (from `kind: 'feat'`).",
        +  "minLength": 1,
        +  "type": "string"
        +}
      • addedInput schema / properties / backgroundRuleId
        Added value: +{
        +  "description": "`_id` of a Background rule (from `kind: 'background'`).",
        +  "minLength": 1,
        +  "type": "string"
        +}
      • addedInput schema / properties / backgroundSkillProficiencies
        Added value: +{
        +  "description": "The background skill picks, when the background grants skills as a CHOICE (`background.skillChoices`). Exactly `background.skillChoices.count` names from `background.skillChoices.options`, no duplicates. Parallel to `skillProficiencies` (the class picks). Omit when the background has no `skillChoices` block; a background's fixed `skillProficiencies` are auto-applied and need no pick.",
        +  "items": {
        +    "type": "string"
        +  },
        +  "type": "array"
        +}
      • addedInput schema / properties / castingAbilityPicks
        Added value: +{
        +  "additionalProperties": {
        +    "enum": [
        +      "strength",
        +      "dexterity",
        +      "constitution",
        +      "intelligence",
        +      "wisdom",
        +      "charisma"
        +    ],
        +    "type": "string"
        +  },
        +  "description": "Spellcasting-ability picks for `spellChoices` blocks that carry `castingAbilityOptions` (the lineage \"Intelligence, Wisdom, or Charisma is your spellcasting ability\" wording). Key is `\"<ruleId>:<blockIndex>\"` (same keying as `spellChoicePicks`); value is ONE lowercase ability name from that block's `castingAbilityOptions`. The projection surfaces `castingAbilityOptions` only when a pick is genuinely required (a fixed ability or a single option self-resolves server-side) — so whenever you see the array, supply a pick or the build rejects the draft. The resolved ability is stamped on each granted spell (`spells[].castingAbility`). A `repeatable` background feat prefixes the key `bg:<featId>:<blockIndex>` (same keying as spellChoicePicks).",
        +  "propertyNames": {
        +    "type": "string"
        +  },
        +  "type": "object"
        +}
      • addedInput schema / properties / classRuleId
        Added value: +{
        +  "description": "Required. `_id` of a base Class rule (from `vault_get_pc_creation_options({ kind: 'class' })`).",
        +  "minLength": 1,
        +  "type": "string"
        +}
      • addedInput schema / properties / description
        Added value: +{
        +  "description": "Character description / biography.",
        +  "type": "string"
        +}
      • addedInput schema / properties / equipmentChoices
        Added value: +{
        +  "additionalProperties": {
        +    "type": "string"
        +  },
        +  "description": "Resolves equipment groups in the chosen bundle. Key is the group parent item `_id` (a `startingEquipmentOptions[].items[]` entry that carries `group.options`); value is the picked member `_id`. Every group in the chosen bundle needs an entry.",
        +  "propertyNames": {
        +    "type": "string"
        +  },
        +  "type": "object"
        +}
      • addedInput schema / properties / image
        Added value: +{
        +  "additionalProperties": {},
        +  "description": "Character portrait — `{ url }`.",
        +  "properties": {
        +    "url": {
        +      "description": "Image URL hosted on Embers Images (or any addressable HTTPS URL).",
        +      "type": "string"
        +    }
        +  },
        +  "type": "object"
        +}
      • addedInput schema / properties / languageChoicePicks
        Added value: +{
        +  "additionalProperties": {
        +    "items": {
        +      "type": "string"
        +    },
        +    "type": "array"
        +  },
        +  "description": "Picks for a background's or species' language-CHOICE grant (`background.languages.choose` / `species.languages.choose`). Key is the granting rule's `_id`; value is exactly `languages.choose.count` names from `languages.choose.options` (an empty options pool means any `constants.languages.options`). The grant's `languages.fixed` are auto-applied and need no pick. Distinct from `languages` (the character's own picks).",
        +  "propertyNames": {
        +    "type": "string"
        +  },
        +  "type": "object"
        +}
      • addedInput schema / properties / languages
        Added value: +{
        +  "description": "The character's OWN chosen language names (e.g. ['Elvish','Draconic']). 'Common' is added server-side. `constants.languages.options` + `pickCount` are the conventional pool and count, but vault stores whatever is passed here — free-form names are allowed and the count is not enforced. (Languages a background/species GRANTS go in `languageChoicePicks`, not here.)",
        +  "items": {
        +    "type": "string"
        +  },
        +  "type": "array"
        +}
      • addedInput schema / properties / name
        Added value: +{
        +  "description": "Character name. Required.",
        +  "minLength": 1,
        +  "type": "string"
        +}
      • addedInput schema / properties / preparedSpellPicks
        Added value: +{
        +  "additionalProperties": {
        +    "items": {
        +      "description": "Mongo `_id` reference (24-character hex string).",
        +      "minLength": 1,
        +      "type": "string"
        +    },
        +    "type": "array"
        +  },
        +  "description": "Which leveled spells the player keeps prepared, for rules carrying a `preparedSpells` count. Key is the granting rule `_id`; value is spell `_id`s drawn from the character's granted leveled spells — `spellChoices` picks, whole-pool fixed grants, and `spellListChoices` picks alike — EXCLUDING spells that are already prepared: cantrips, and any spell granted by a block whose `prepared` flag is true (an always-prepared grant; the options projection ships `prepared` on each block so you can tell). The required count is the grant's count CLAMPED to that pool's size — send exactly min(count, preparable leveled spells). A `repeatable` feat filling the background slot keys `bg:<featId>` instead of `<featId>`.",
        +  "propertyNames": {
        +    "type": "string"
        +  },
        +  "type": "object"
        +}
      • addedInput schema / properties / proficiencyChoicePicks
        Added value: +{
        +  "additionalProperties": {
        +    "items": {
        +      "type": "string"
        +    },
        +    "type": "array"
        +  },
        +  "description": "Picks for proficiencyChoices grants across ALL applied rules (class/species/feat/abilities). Key is `\"<ruleId>:<grantIndex>\"` (the Rule `_id` and the 0-based index into that rule's `proficiencyChoices`); value is the chosen names (skills/tools/saves/weapons/armor/languages). Only supply for grants where `count` < the option-pool size — fixed grants (count >= pool) are auto-applied and need no pick. A grant with `level: \"expertise\"` draws from the character's PROFICIENT skills (proficiency from every source applies first, then expertise), granting the expertise state rather than proficiency. A `repeatable` feat filling the background slot prefixes its keys `bg:<featId>:<grantIndex>` (not `<featId>:<grantIndex>`).",
        +  "propertyNames": {
        +    "type": "string"
        +  },
        +  "type": "object"
        +}
      • addedInput schema / properties / ruleset
        Added value: +{
        +  "default": "5e24",
        +  "description": "Ruleset. Only '5e24' supports guided creation today.",
        +  "enum": [
        +    "5e24"
        +  ],
        +  "type": "string"
        +}
      • addedInput schema / properties / skillProficiencies
        Added value: +{
        +  "description": "The class skill picks. Exactly `class.skillChoices.count` names, each from `class.skillChoices.options`, no duplicates. Empty array if the class grants no skill choices.",
        +  "items": {
        +    "type": "string"
        +  },
        +  "type": "array"
        +}
      • addedInput schema / properties / speciesAbilityChoices
        Added value: +{
        +  "additionalProperties": {
        +    "items": {
        +      "type": "string"
        +    },
        +    "type": "array"
        +  },
        +  "description": "Same as `abilityChoices`, for a species ability's `choice` (e.g. a Human's 'Versatile' → an Origin feat). A picked option's own sub-choices (any type — Ability or Feat) go in the proficiency/spell pick maps keyed by that option's `_id`.",
        +  "propertyNames": {
        +    "type": "string"
        +  },
        +  "type": "object"
        +}
      • addedInput schema / properties / speciesRuleId
        Added value: +{
        +  "description": "`_id` of a Species/Race rule (from `kind: 'species'`).",
        +  "minLength": 1,
        +  "type": "string"
        +}
      • addedInput schema / properties / spellChoicePicks
        Added value: +{
        +  "additionalProperties": {
        +    "items": {
        +      "description": "Mongo `_id` reference (24-character hex string).",
        +      "minLength": 1,
        +      "type": "string"
        +    },
        +    "type": "array"
        +  },
        +  "description": "Picks for `spellChoices` blocks across ALL applied rules (class/species/feat/abilities). Key is `\"<ruleId>:<blockIndex>\"` (the Rule `_id` and the 0-based index into that rule's `spellChoices` AS PROJECTED — the array may contain null entries holding the position of blocks that grant nothing at level 1; count them when indexing, never compact the array). Value is the chosen spell `_id`s. Only supply where a block's `count` < its option-pool size — a whole-pool block is granted automatically. Each block's options come from `vault_get_pc_creation_options` (an applied ability/feat's `spellChoices[].options`). A `repeatable` feat filling the background slot prefixes its keys `bg:<featId>:<blockIndex>`.",
        +  "propertyNames": {
        +    "type": "string"
        +  },
        +  "type": "object"
        +}
      • addedInput schema / properties / spellListChoicePicks
        Added value: +{
        +  "additionalProperties": {
        +    "additionalProperties": {},
        +    "properties": {
        +      "castingAbility": {
        +        "enum": [
        +          "strength",
        +          "dexterity",
        +          "constitution",
        +          "intelligence",
        +          "wisdom",
        +          "charisma"
        +        ],
        +        "type": "string"
        +      },
        +      "category": {
        +        "type": "string"
        +      },
        +      "picks": {
        +        "additionalProperties": {
        +          "items": {
        +            "description": "Mongo `_id` reference (24-character hex string).",
        +            "minLength": 1,
        +            "type": "string"
        +          },
        +          "type": "array"
        +        },
        +        "propertyNames": {
        +          "type": "string"
        +        },
        +        "type": "object"
        +      }
        +    },
        +    "type": "object"
        +  },
        +  "description": "Picks for `spellListChoices` blocks (the Magic Initiate shape: choose ONE class list, then spells from that one list). Key is `\"<ruleId>:<blockIndex>\"` (the projected array may contain null entries holding the position of blocks the build skips — count them when indexing, never compact); value is `{ category, picks }` where `category` is one of the block's `categories` and `picks` is `{ \"<pickIndex>\": [spellId, …] }` — the chosen spells for each pick, drawn from that pick's `optionsByCategory[category]`. When the block carries `castingAbilityOptions`, also set `castingAbility` (one lowercase ability name from those options) — the build rejects the draft without it. A `repeatable` feat filling the background slot prefixes its keys `bg:<featId>:<blockIndex>`.",
        +  "propertyNames": {
        +    "type": "string"
        +  },
        +  "type": "object"
        +}
      • addedInput schema / properties / startingEquipmentLabel
        Added value: +{
        +  "description": "The chosen equipment bundle — must equal one `class.startingEquipmentOptions[].label` exactly.",
        +  "type": "string"
        +}
      • addedInput schema / properties / token
        Added value: +{
        +  "additionalProperties": {},
        +  "description": "Default battlemap token art — `{ url }`.",
        +  "properties": {
        +    "url": {
        +      "description": "Image URL hosted on Embers Images (or any addressable HTTPS URL).",
        +      "type": "string"
        +    }
        +  },
        +  "type": "object"
        +}
      • addedInput schema / properties / toolProficiencies
        Added value: +{
        +  "description": "The class tool picks. Exactly `class.toolChoices.count` names from `class.toolChoices.options`. If an option is a group, pick a concrete member name, not the group. Empty array if none.",
        +  "items": {
        +    "type": "string"
        +  },
        +  "type": "array"
        +}
      • addedInput schema / properties / weaponAbilityChoices
        Added value: +{
        +  "additionalProperties": {
        +    "enum": [
        +      "strength",
        +      "dexterity"
        +    ],
        +    "type": "string"
        +  },
        +  "description": "For finesse weapons in the chosen bundle: key is the item `_id`, value is the attack ability ('strength' or 'dexterity').",
        +  "propertyNames": {
        +    "type": "string"
        +  },
        +  "type": "object"
        +}
      • addedInput schema / required
        Added value: +[
        +  "name",
        +  "classRuleId",
        +  "abilityScoreMethod",
        +  "abilityScoreAssignments",
        +  "skillProficiencies",
        +  "toolProficiencies",
        +  "startingEquipmentLabel"
        +]
    • Changedvault_create_character26 fields changed
      • addedInput schema / $schema
        Added value: +"http://json-schema.org/draft-07/schema#"
      • addedInput schema / additionalProperties
        Added value: +{}
      • addedInput schema / properties / actions
        Added value: +{
        +  "items": {
        +    "additionalProperties": {},
        +    "properties": {
        +      "_item": {
        +        "description": "Optional back-reference to the Vault Item this action was built from.",
        +        "minLength": 1,
        +        "type": "string"
        +      },
        +      "_rule": {
        +        "description": "Optional back-reference to the Vault Rule this action was built from.",
        +        "minLength": 1,
        +        "type": "string"
        +      },
        +      "_spell": {
        +        "description": "Optional back-reference to the Vault Spell this action was built from.",
        +        "minLength": 1,
        +        "type": "string"
        +      },
        +      "actions": {
        +        "description": "PF Playtest action-economy marker (F/1/2/3/R).",
        +        "type": "string"
        +      },
        +      "attack": {
        +        "additionalProperties": {},
        +        "properties": {
        +          "attribute": {
        +            "description": "Ability driving the to-hit roll (e.g. 'strength', 'charisma' for spell attacks).",
        +            "type": "string"
        +          },
        +          "magic": {
        +            "type": "number"
        +          },
        +          "misc": {
        +            "type": "number"
        +          },
        +          "proficiency": {
        +            "type": "number"
        +          },
        +          "skill": {
        +            "type": "string"
        +          }
        +        },
        +        "type": "object"
        +      },
        +      "damage": {
        +        "additionalProperties": {},
        +        "properties": {
        +          "attribute": {
        +            "description": "Ability whose modifier is added to damage.",
        +            "type": "string"
        +          },
        +          "critical": {
        +            "type": "string"
        +          },
        +          "dice": {
        +            "description": "Base damage dice expression (e.g. '2d8'). Additional damage types live in `description` per Rule 11.",
        +            "type": "string"
        +          },
        +          "magic": {
        +            "type": "number"
        +          },
        +          "misc": {
        +            "type": "number"
        +          },
        +          "type": {
        +            "description": "Damage type ('piercing', 'fire', etc.). Source-exact, capitalize if the source does.",
        +            "type": "string"
        +          }
        +        },
        +        "type": "object"
        +      },
        +      "description": {
        +        "type": "string"
        +      },
        +      "name": {
        +        "type": "string"
        +      },
        +      "proficient": {
        +        "type": "boolean"
        +      },
        +      "range": {
        +        "type": "string"
        +      },
        +      "rof": {
        +        "description": "Savage Worlds Rate of Fire.",
        +        "type": "number"
        +      },
        +      "summary": {
        +        "type": "string"
        +      },
        +      "type": {
        +        "description": "Action type. 5e24 uses 'Melee' / 'Range' / 'Special' / 'Reaction' / 'Legendary' / 'Bonus'.",
        +        "type": "string"
        +      }
        +    },
        +    "type": "object"
        +  },
        +  "type": "array"
        +}
      • addedInput schema / properties / active
        Added value: +{
        +  "type": "boolean"
        +}
      • addedInput schema / properties / aspects
        Added value: +{
        +  "items": {
        +    "additionalProperties": {},
        +    "properties": {
        +      "description": {
        +        "type": "string"
        +      },
        +      "kind": {
        +        "description": "One of 'high concept', 'trouble', 'character', 'consequence'.",
        +        "type": "string"
        +      },
        +      "name": {
        +        "description": "The aspect's phrase. A consequence slot carries its cost while blank.",
        +        "type": "string"
        +      },
        +      "shifts": {
        +        "description": "Consequence/condition slots only: harm absorbed. Fate: 2 Mild, 4 Moderate, 6 Severe, 8 Extreme (Fate Accelerated omits Extreme). Demon Hunters conditions: 5 Mild, 10 Moderate, 15 Severe.",
        +        "type": "number"
        +      }
        +    },
        +    "type": "object"
        +  },
        +  "type": "array"
        +}
      • addedInput schema / properties / attributes
        Added value: +{
        +  "items": {
        +    "additionalProperties": {},
        +    "properties": {
        +      "misc": {
        +        "description": "Misc bonus on the save (5e/5e24). Used for high-PB monster compensation.",
        +        "type": "number"
        +      },
        +      "name": {
        +        "description": "Ability name: strength / dexterity / constitution / intelligence / wisdom / charisma. Lowercase.",
        +        "type": "string"
        +      },
        +      "proficient": {
        +        "description": "Save proficiency flag (5e/5e24). When true, PB is added to the save.",
        +        "type": "boolean"
        +      },
        +      "score": {
        +        "description": "Raw ability score (e.g. 17). Modifier is derived by the sheet.",
        +        "type": "number"
        +      },
        +      "temp": {
        +        "type": "number"
        +      }
        +    },
        +    "type": "object"
        +  },
        +  "type": "array"
        +}
      • addedInput schema / properties / core
        Added value: +{
        +  "additionalProperties": {},
        +  "properties": {
        +    "age": {
        +      "type": "string"
        +    },
        +    "alignment": {
        +      "type": "string"
        +    },
        +    "ancestry": {
        +      "type": "string"
        +    },
        +    "background": {
        +      "type": "string"
        +    },
        +    "baseAttackBonus": {
        +      "type": "number"
        +    },
        +    "charisma": {
        +      "type": "string"
        +    },
        +    "class": {
        +      "description": "Character class as free-form text. PCs use a Class rule via rules[]; this field is the display string.",
        +      "type": "string"
        +    },
        +    "cr": {
        +      "type": "string"
        +    },
        +    "deity": {
        +      "type": "string"
        +    },
        +    "experience": {
        +      "description": "Character-level XP (no commas). For monsters, the value from the CR→level XP table.",
        +      "type": "string"
        +    },
        +    "eyes": {
        +      "type": "string"
        +    },
        +    "gender": {
        +      "type": "string"
        +    },
        +    "hair": {
        +      "type": "string"
        +    },
        +    "height": {
        +      "type": "string"
        +    },
        +    "homeland": {
        +      "type": "string"
        +    },
        +    "languages": {
        +      "type": "string"
        +    },
        +    "proficiencies": {
        +      "type": "string"
        +    },
        +    "pronouns": {
        +      "description": "The character's pronouns as free-form text (e.g. 'she/her', 'they/them').",
        +      "type": "string"
        +    },
        +    "race": {
        +      "description": "Creature type for monsters (e.g. 'Elemental', 'Humanoid', 'Dragon (Chromatic)'); race for PCs.",
        +      "type": "string"
        +    },
        +    "refresh": {
        +      "description": "Session-start resource: fate points (Fate — Refresh) or faith dice (Demon Hunters — Devotion). The total the character resets to at the start of a session.",
        +      "type": "number"
        +    },
        +    "size": {
        +      "description": "Creature size. Exact source text including 'or' for variable sizes ('Medium or Small').",
        +      "type": "string"
        +    },
        +    "skin": {
        +      "type": "string"
        +    },
        +    "spellCastingAttribute": {
        +      "type": "string"
        +    },
        +    "weight": {
        +      "type": "string"
        +    }
        +  },
        +  "type": "object"
        +}
      • addedInput schema / properties / dead
        Added value: +{
        +  "type": "boolean"
        +}
      • addedInput schema / properties / defense
        Added value: +{
        +  "additionalProperties": {},
        +  "properties": {
        +    "armorClass": {
        +      "additionalProperties": {},
        +      "description": "Layered AC rows the sheet sums. IMPORTANT (5e24): when the character's `settings.autoPassiveBonuses` is true — the default for new 5e24 characters — the `armor` and `shield` rows are DERIVED from equipped items and recomputed on every sheet load, so writing them here gets overwritten. Change AC by setting `equipped: true/false` on the character's armor/shield items instead. When the toggle is false (and on all other rulesets), these rows are manually authored and writing them here is correct. `magic` and `misc` are manual in both modes. Check the toggle with vault_get_character before writing.",
        +      "properties": {
        +        "armor": {
        +          "additionalProperties": {},
        +          "properties": {
        +            "bonus": {
        +              "description": "Base AC value the sheet adds DEX to. See the 5e24 monster guide Rule 1 for the math.",
        +              "type": "number"
        +            },
        +            "checkPenalty": {
        +              "type": "number"
        +            },
        +            "description": {
        +              "description": "Armor name ('Natural Armor', 'Chain Shirt') or null when AC derives from DEX only.",
        +              "type": "string"
        +            },
        +            "heavy": {
        +              "description": "True suppresses DEX contribution entirely (heavy armor).",
        +              "type": "boolean"
        +            },
        +            "maxDex": {
        +              "type": "number"
        +            },
        +            "medium": {
        +              "description": "True caps DEX contribution to +2 (medium armor).",
        +              "type": "boolean"
        +            },
        +            "proficiency": {
        +              "type": "number"
        +            },
        +            "speed": {
        +              "type": "string"
        +            },
        +            "speedPenalty": {
        +              "type": "string"
        +            },
        +            "spellFail": {
        +              "type": "string"
        +            },
        +            "touchBonus": {
        +              "type": "number"
        +            }
        +          },
        +          "type": "object"
        +        },
        +        "arms": {
        +          "additionalProperties": {},
        +          "properties": {
        +            "bonus": {
        +              "type": "number"
        +            },
        +            "description": {
        +              "type": "string"
        +            }
        +          },
        +          "type": "object"
        +        },
        +        "deflection": {
        +          "additionalProperties": {},
        +          "properties": {
        +            "bonus": {
        +              "type": "number"
        +            },
        +            "description": {
        +              "type": "string"
        +            }
        +          },
        +          "type": "object"
        +        },
        +        "dodge": {
        +          "additionalProperties": {},
        +          "properties": {
        +            "bonus": {
        +              "type": "number"
        +            },
        +            "description": {
        +              "type": "string"
        +            }
        +          },
        +          "type": "object"
        +        },
        +        "head": {
        +          "additionalProperties": {},
        +          "properties": {
        +            "bonus": {
        +              "type": "number"
        +            },
        +            "description": {
        +              "type": "string"
        +            }
        +          },
        +          "type": "object"
        +        },
        +        "legs": {
        +          "additionalProperties": {},
        +          "properties": {
        +            "bonus": {
        +              "type": "number"
        +            },
        +            "description": {
        +              "type": "string"
        +            }
        +          },
        +          "type": "object"
        +        },
        +        "magic": {
        +          "additionalProperties": {},
        +          "properties": {
        +            "bonus": {
        +              "type": "number"
        +            },
        +            "description": {
        +              "type": "string"
        +            }
        +          },
        +          "type": "object"
        +        },
        +        "misc": {
        +          "additionalProperties": {},
        +          "properties": {
        +            "bonus": {
        +              "type": "number"
        +            },
        +            "description": {
        +              "type": "string"
        +            }
        +          },
        +          "type": "object"
        +        },
        +        "natural": {
        +          "additionalProperties": {},
        +          "properties": {
        +            "bonus": {
        +              "type": "number"
        +            },
        +            "description": {
        +              "type": "string"
        +            }
        +          },
        +          "type": "object"
        +        },
        +        "shield": {
        +          "additionalProperties": {},
        +          "properties": {
        +            "bonus": {
        +              "type": "number"
        +            },
        +            "checkPenalty": {
        +              "type": "number"
        +            },
        +            "description": {
        +              "type": "string"
        +            },
        +            "maxDex": {
        +              "type": "number"
        +            },
        +            "proficiency": {
        +              "type": "number"
        +            },
        +            "raised": {
        +              "type": "boolean"
        +            },
        +            "spellFail": {
        +              "type": "number"
        +            },
        +            "touchBonus": {
        +              "type": "number"
        +            }
        +          },
        +          "type": "object"
        +        }
        +      },
        +      "type": "object"
        +    },
        +    "damageReduction": {
        +      "type": "string"
        +    },
        +    "deathSaves": {
        +      "additionalProperties": {},
        +      "properties": {
        +        "failures": {
        +          "items": {
        +            "type": "string"
        +          },
        +          "type": "array"
        +        },
        +        "successes": {
        +          "items": {
        +            "type": "string"
        +          },
        +          "type": "array"
        +        }
        +      },
        +      "type": "object"
        +    },
        +    "dying": {
        +      "additionalProperties": {},
        +      "properties": {
        +        "current": {
        +          "type": "number"
        +        },
        +        "wounds": {
        +          "type": "number"
        +        }
        +      },
        +      "type": "object"
        +    },
        +    "exhaustion": {
        +      "description": "5e24 Exhaustion level (0-6). Absent = 0 (not exhausted). Each level is -2 to d20 Tests and -5 ft Speed; level 6 = death. A Long Rest via the vault rest control reduces it by 1.",
        +      "maximum": 6,
        +      "minimum": 0,
        +      "type": "integer"
        +    },
        +    "health": {
        +      "additionalProperties": {},
        +      "properties": {
        +        "fatigue": {
        +          "type": "number"
        +        },
        +        "incapacitated": {
        +          "type": "boolean"
        +        },
        +        "wounds": {
        +          "type": "number"
        +        }
        +      },
        +      "type": "object"
        +    },
        +    "hitDice": {
        +      "additionalProperties": {},
        +      "properties": {
        +        "current": {
        +          "description": "Unspent hit dice count. When `pools` is present (5e24 class characters), this is the derived sum of pool currents — keep it consistent with pools on write.",
        +          "type": "number"
        +        },
        +        "dice": {
        +          "description": "Without `pools` (monsters, non-5e24): per-die expression, NOT the multiplied total — size-mapped Tiny d4 / Small d6 / Medium d8 / Large d10 / Huge d12 / Gargantuan d20, see monster guide Rule 20. When `pools` is present (5e24 class characters): the derived compound string ('5d10 + 5d6') — keep it consistent with pools on write.",
        +          "type": "string"
        +        },
        +        "pools": {
        +          "description": "5e24 per-die-size Hit Dice pools — the AUTHORITATIVE representation (one entry per die size a multiclass character has). Maintained by creation, level-up, and a one-shot backfill; player edits win. The server does NOT re-derive the legacy fields on write, so when writing hit dice for a character with pools, write pools AND the legacy current/dice consistently (current = sum of pool currents; dice = compound string).",
        +          "items": {
        +            "additionalProperties": {},
        +            "properties": {
        +              "current": {
        +                "maximum": 9007199254740991,
        +                "minimum": 0,
        +                "type": "integer"
        +              },
        +              "dice": {
        +                "description": "Die size of this pool, e.g. 'd10'.",
        +                "type": "string"
        +              },
        +              "maximum": {
        +                "maximum": 9007199254740991,
        +                "minimum": 0,
        +                "type": "integer"
        +              }
        +            },
        +            "type": "object"
        +          },
        +          "type": "array"
        +        }
        +      },
        +      "type": "object"
        +    },
        +    "hitPoints": {
        +      "additionalProperties": {},
        +      "properties": {
        +        "current": {
        +          "type": "number"
        +        },
        +        "maximum": {
        +          "type": "number"
        +        },
        +        "temp": {
        +          "type": "number"
        +        }
        +      },
        +      "type": "object"
        +    },
        +    "parryBonus": {
        +      "type": "number"
        +    },
        +    "savingThrows": {
        +      "items": {
        +        "additionalProperties": {},
        +        "properties": {
        +          "attribute": {
        +            "type": "string"
        +          },
        +          "base": {
        +            "type": "number"
        +          },
        +          "magic": {
        +            "type": "number"
        +          },
        +          "misc": {
        +            "type": "number"
        +          },
        +          "name": {
        +            "type": "string"
        +          },
        +          "proficiency": {
        +            "type": "number"
        +          },
        +          "temp": {
        +            "type": "number"
        +          }
        +        },
        +        "type": "object"
        +      },
        +      "type": "array"
        +    },
        +    "spellResistance": {
        +      "type": "string"
        +    },
        +    "toughnessBonus": {
        +      "type": "number"
        +    }
        +  },
        +  "type": "object"
        +}
      • addedInput schema / properties / description
        Added value: +{
        +  "type": "string"
        +}
      • addedInput schema / properties / image
        Added value: +{
        +  "additionalProperties": {},
        +  "properties": {
        +    "url": {
        +      "description": "Image URL hosted on Embers Images (or any addressable HTTPS URL).",
        +      "type": "string"
        +    }
        +  },
        +  "type": "object"
        +}
      • addedInput schema / properties / items
        Added value: +{
        +  "items": {
        +    "additionalProperties": {},
        +    "properties": {
        +      "_ref": {
        +        "description": "Mongo `_id` reference (24-character hex string).",
        +        "minLength": 1,
        +        "type": "string"
        +      },
        +      "armorCategory": {
        +        "type": "string"
        +      },
        +      "armorClass": {
        +        "type": "number"
        +      },
        +      "carried": {
        +        "type": "boolean"
        +      },
        +      "cost": {
        +        "type": "number"
        +      },
        +      "damageDice": {
        +        "type": "string"
        +      },
        +      "damageType": {
        +        "items": {
        +          "type": "string"
        +        },
        +        "type": "array"
        +      },
        +      "description": {
        +        "type": "string"
        +      },
        +      "detail": {
        +        "type": "string"
        +      },
        +      "equipSlot": {
        +        "type": "string"
        +      },
        +      "equipSlots": {
        +        "items": {
        +          "type": "string"
        +        },
        +        "type": "array"
        +      },
        +      "equipped": {
        +        "description": "Monsters: ALWAYS false. Never set equipped/equipSlot on a monster's items.",
        +        "type": "boolean"
        +      },
        +      "image": {
        +        "additionalProperties": {},
        +        "properties": {
        +          "url": {
        +            "description": "Image URL hosted on Embers Images (or any addressable HTTPS URL).",
        +            "type": "string"
        +          }
        +        },
        +        "type": "object"
        +      },
        +      "mastery": {
        +        "type": "string"
        +      },
        +      "maxDexModifier": {
        +        "type": "number"
        +      },
        +      "name": {
        +        "type": "string"
        +      },
        +      "properties": {
        +        "items": {
        +          "additionalProperties": {},
        +          "properties": {
        +            "ammoType": {
        +              "type": "string"
        +            },
        +            "damage": {
        +              "type": "string"
        +            },
        +            "display": {
        +              "type": "string"
        +            },
        +            "name": {
        +              "type": "string"
        +            },
        +            "range": {
        +              "additionalProperties": {},
        +              "properties": {
        +                "long": {
        +                  "type": "number"
        +                },
        +                "normal": {
        +                  "type": "number"
        +                }
        +              },
        +              "type": "object"
        +            }
        +          },
        +          "type": "object"
        +        },
        +        "type": "array"
        +      },
        +      "quantity": {
        +        "type": "number"
        +      },
        +      "sourceSpell": {
        +        "description": "Auto-managed. Link to the spell that manufactured this companion armor item (e.g. Mage Armor, which the vault sheet offers as an equippable Light armor). The sheet sets and maintains it; if it's present on an item you're editing, preserve it verbatim, and never set, change, or invent it. Dropping it on a round-trip de-links the companion and leaves a duplicate item on the sheet.",
        +        "minLength": 1,
        +        "type": "string"
        +      },
        +      "stealthDisadvantage": {
        +        "type": "boolean"
        +      },
        +      "stock": {
        +        "type": "boolean"
        +      },
        +      "strengthRequirement": {
        +        "type": "number"
        +      },
        +      "summary": {
        +        "type": "string"
        +      },
        +      "twoHandedGrip": {
        +        "type": "boolean"
        +      },
        +      "type": {
        +        "type": "string"
        +      },
        +      "weaponType": {
        +        "type": "string"
        +      },
        +      "weight": {
        +        "type": "number"
        +      }
        +    },
        +    "type": "object"
        +  },
        +  "type": "array"
        +}
      • addedInput schema / properties / name
        Added value: +{
        +  "description": "Character name. Required.",
        +  "minLength": 1,
        +  "type": "string"
        +}
      • addedInput schema / properties / notes
        Added value: +{
        +  "items": {
        +    "additionalProperties": {},
        +    "properties": {
        +      "description": {
        +        "description": "Note body. Free-form markdown.",
        +        "type": "string"
        +      },
        +      "name": {
        +        "description": "Note title. Used as the visible heading on the character sheet.",
        +        "type": "string"
        +      }
        +    },
        +    "type": "object"
        +  },
        +  "type": "array"
        +}
      • addedInput schema / properties / offense
        Added value: +{
        +  "additionalProperties": {},
        +  "properties": {
        +    "initiative": {
        +      "additionalProperties": {},
        +      "properties": {
        +        "attribute": {
        +          "description": "Ability whose modifier drives initiative. Typically 'dexterity'.",
        +          "type": "string"
        +        },
        +        "misc": {
        +          "description": "Misc bonus added to initiative beyond the attribute modifier.",
        +          "type": "number"
        +        }
        +      },
        +      "type": "object"
        +    },
        +    "perception": {
        +      "additionalProperties": {},
        +      "properties": {
        +        "attribute": {
        +          "type": "string"
        +        },
        +        "misc": {
        +          "type": "number"
        +        },
        +        "proficiency": {
        +          "type": "number"
        +        }
        +      },
        +      "type": "object"
        +    },
        +    "spellCasting": {
        +      "additionalProperties": {},
        +      "properties": {
        +        "attribute": {
        +          "type": "string"
        +        },
        +        "misc": {
        +          "type": "number"
        +        },
        +        "proficiency": {
        +          "type": "number"
        +        }
        +      },
        +      "type": "object"
        +    }
        +  },
        +  "type": "object"
        +}
      • addedInput schema / properties / personality
        Added value: +{
        +  "additionalProperties": {},
        +  "properties": {
        +    "bonds": {
        +      "type": "string"
        +    },
        +    "flaws": {
        +      "type": "string"
        +    },
        +    "ideals": {
        +      "type": "string"
        +    },
        +    "traits": {
        +      "type": "string"
        +    }
        +  },
        +  "type": "object"
        +}
      • addedInput schema / properties / rules
        Added value: +{
        +  "items": {
        +    "additionalProperties": {},
        +    "properties": {
        +      "_ref": {
        +        "description": "Master Rule ObjectId. Present when the snapshot points at a Vault Rule (PC catalog content); null on stock-monster-style inline rules.",
        +        "minLength": 1,
        +        "type": "string"
        +      },
        +      "actions": {
        +        "type": "string"
        +      },
        +      "description": {
        +        "type": "string"
        +      },
        +      "detail": {
        +        "type": "string"
        +      },
        +      "level": {
        +        "description": "Per-instance class level (this character's level in this class) — only meaningful on a Class snapshot. Stored and read directly, never derived; total character level stays XP-derived. Absent on non-Class snapshots.",
        +        "type": "number"
        +      },
        +      "name": {
        +        "type": "string"
        +      },
        +      "statBonuses": {
        +        "items": {
        +          "additionalProperties": {},
        +          "properties": {
        +            "attribute": {
        +              "description": "For valueType: 'attribute' — which ability's modifier to use.",
        +              "type": "string"
        +            },
        +            "audience": {
        +              "description": "Who the bonus contributes to. Absent = self.",
        +              "enum": [
        +                "self",
        +                "ally",
        +                "any",
        +                "target",
        +                "enemy"
        +              ],
        +              "type": "string"
        +            },
        +            "dice": {
        +              "description": "For valueType: 'dice' — dice expression (e.g. '1d4').",
        +              "type": "string"
        +            },
        +            "durationCount": {
        +              "description": "Numeric count paired with durationUnit (e.g. count: 3, unit: 'round').",
        +              "maximum": 9007199254740991,
        +              "minimum": 0,
        +              "type": "integer"
        +            },
        +            "durationUnit": {
        +              "description": "How long the bonus persists once fired. Only meaningful for event-driven bonuses.",
        +              "enum": [
        +                "instantaneous",
        +                "untilStartOfNextTurn",
        +                "untilEndOfNextTurn",
        +                "round",
        +                "minute",
        +                "hour",
        +                "untilShortRest",
        +                "untilLongRest"
        +              ],
        +              "type": "string"
        +            },
        +            "fixed": {
        +              "description": "For valueType: 'fixed' — the literal numeric contribution.",
        +              "type": "number"
        +            },
        +            "progression": {
        +              "description": "For valueType: 'byLevel' — per-level rows; walker picks the row with level <= current level.",
        +              "items": {
        +                "additionalProperties": {},
        +                "properties": {
        +                  "dice": {
        +                    "type": "string"
        +                  },
        +                  "flat": {
        +                    "type": "number"
        +                  },
        +                  "level": {
        +                    "maximum": 20,
        +                    "minimum": 1,
        +                    "type": "integer"
        +                  }
        +                },
        +                "type": "object"
        +              },
        +              "type": "array"
        +            },
        +            "range": {
        +              "description": "Aura radius in feet for ally/any-audience bonuses (Aura of Protection's 10 ft.). Absent = no range filter.",
        +              "maximum": 9007199254740991,
        +              "minimum": 0,
        +              "type": "integer"
        +            },
        +            "requires": {
        +              "description": "Optional predicate list that gates this bonus. Absent / empty = always-on.",
        +              "items": {
        +                "additionalProperties": {},
        +                "properties": {
        +                  "armorCategories": {
        +                    "description": "For 'equipped' + slot:armor: armor category list (Light / Medium / Heavy). OR semantics — match any.",
        +                    "items": {
        +                      "type": "string"
        +                    },
        +                    "type": "array"
        +                  },
        +                  "condition": {
        +                    "description": "For 'condition' predicates: the character-state condition to gate on (5e24 named conditions and ongoing-action states).",
        +                    "enum": [
        +                      "blinded",
        +                      "charmed",
        +                      "dazed",
        +                      "deafened",
        +                      "exhaustion",
        +                      "frightened",
        +                      "grappled",
        +                      "incapacitated",
        +                      "invisible",
        +                      "paralyzed",
        +                      "petrified",
        +                      "poisoned",
        +                      "prone",
        +                      "restrained",
        +                      "stunned",
        +                      "unconscious",
        +                      "concentrating",
        +                      "grappling",
        +                      "dodging",
        +                      "hiding",
        +                      "raging"
        +                    ],
        +                    "type": "string"
        +                  },
        +                  "equipSlot": {
        +                    "description": "Body slot the matched weapon must occupy. mainHand / offHand. Resolved via getRequiredSlots so two-handed grips occupy both.",
        +                    "enum": [
        +                      "mainHand",
        +                      "offHand"
        +                    ],
        +                    "type": "string"
        +                  },
        +                  "negate": {
        +                    "description": "true inverts the predicate — 'while NOT matching' instead of 'while matching'.",
        +                    "type": "boolean"
        +                  },
        +                  "slot": {
        +                    "description": "For 'equipped' predicates: the body category to match (armor / shield / weapon).",
        +                    "enum": [
        +                      "armor",
        +                      "shield",
        +                      "weapon"
        +                    ],
        +                    "type": "string"
        +                  },
        +                  "type": {
        +                    "description": "Predicate type. 'equipped' = character-scoped (gates on what's equipped). 'attackingWeapon' = attack-scoped (gates on the current action's source weapon). 'condition' = gates on a character-state condition.",
        +                    "enum": [
        +                      "equipped",
        +                      "attackingWeapon",
        +                      "condition"
        +                    ],
        +                    "type": "string"
        +                  },
        +                  "weaponProperties": {
        +                    "description": "For 'equipped' + slot:weapon OR 'attackingWeapon': weapon-property list. AND semantics — match all.",
        +                    "items": {
        +                      "type": "string"
        +                    },
        +                    "type": "array"
        +                  }
        +                },
        +                "type": "object"
        +              },
        +              "type": "array"
        +            },
        +            "requiresLogic": {
        +              "description": "How `requires` predicates compose. 'and' (default) = ALL must hold. 'or' = ANY one is sufficient.",
        +              "enum": [
        +                "and",
        +                "or"
        +              ],
        +              "type": "string"
        +            },
        +            "target": {
        +              "description": "Stat the bonus contributes to (e.g. 'skills.Acrobatics.misc', 'attributes.strength.misc').",
        +              "type": "string"
        +            },
        +            "trigger": {
        +              "description": "Action-economy / cost shape of the bonus. passive / toggled / reaction / perRoll / resource / targetBound.",
        +              "enum": [
        +                "passive",
        +                "toggled",
        +                "reaction",
        +                "perRoll",
        +                "resource",
        +                "targetBound"
        +              ],
        +              "type": "string"
        +            },
        +            "triggerEvent": {
        +              "description": "Game-time event that fires the bonus (onHit / onDamage / startOfYourTurn / etc.). Absent = not event-driven (passive walker contributes whenever `requires` holds).",
        +              "enum": [
        +                "onHit",
        +                "onMiss",
        +                "onDamage",
        +                "startOfYourTurn",
        +                "endOfYourTurn",
        +                "startOfTargetTurn",
        +                "endOfTargetTurn"
        +              ],
        +              "type": "string"
        +            },
        +            "types": {
        +              "description": "Damage type tags for damage.* targets. No-op for non-damage targets.",
        +              "items": {
        +                "type": "string"
        +              },
        +              "type": "array"
        +            },
        +            "valueType": {
        +              "description": "How the contribution is computed. 'fixed' uses `fixed`; 'attribute' uses the mod of `attribute`; 'attackAttribute' uses the action's attack-roll ability (per-attack only); others scale by level/PB/dice.",
        +              "enum": [
        +                "fixed",
        +                "attribute",
        +                "proficiency",
        +                "level",
        +                "halfLevel",
        +                "dice",
        +                "byLevel",
        +                "attackAttribute"
        +              ],
        +              "type": "string"
        +            }
        +          },
        +          "type": "object"
        +        },
        +        "type": "array"
        +      },
        +      "stock": {
        +        "type": "boolean"
        +      },
        +      "summary": {
        +        "type": "string"
        +      },
        +      "type": {
        +        "description": "Rule type (Ability / Feat / Class / Background / etc.). Vault validates against its rulestype enum on save.",
        +        "type": "string"
        +      }
        +    },
        +    "type": "object"
        +  },
        +  "type": "array"
        +}
      • addedInput schema / properties / ruleset
        Added value: +{
        +  "description": "Ruleset code (e.g. '5th Edition', '5e24', 'PFRPG', 'Savage Worlds'). Required. Restricted rulesets require an entitlement grant on the account — vault answers 403 for ungranted or unknown codes. Check list_rulesets for the codes this account can use.",
        +  "minLength": 1,
        +  "type": "string"
        +}
      • addedInput schema / properties / settings
        Added value: +{
        +  "additionalProperties": {},
        +  "properties": {
        +    "autoPassiveBonuses": {
        +      "description": "When true, the per-character rules engine layer contributes statBonuses from rules / items / feats. On 5e24 it ALSO derives the armor/shield rows of defense.armorClass from equipped items, recomputed on every sheet load — manual writes to those rows do not stick while this is true. Monsters should set this to false.",
        +      "type": "boolean"
        +    },
        +    "hiddenSections": {
        +      "description": "Sheet-section keys the player chose to hide while the section is empty ('spells', 'abilities', 'feats', 'origin', 'actionCards', 'hindrances', 'edges', 'stunts', 'extras'). A section with content always renders regardless of this list — the preference means 'hide when empty', never 'hide my data'.",
        +      "items": {
        +        "maxLength": 64,
        +        "type": "string"
        +      },
        +      "maxItems": 20,
        +      "type": "array"
        +    }
        +  },
        +  "type": "object"
        +}
      • addedInput schema / properties / skills
        Added value: +{
        +  "items": {
        +    "additionalProperties": {},
        +    "properties": {
        +      "attribute": {
        +        "type": "string"
        +      },
        +      "classSkill": {
        +        "type": "boolean"
        +      },
        +      "description": {
        +        "type": "string"
        +      },
        +      "expertise": {
        +        "type": "boolean"
        +      },
        +      "misc": {
        +        "type": "number"
        +      },
        +      "name": {
        +        "type": "string"
        +      },
        +      "passiveMisc": {
        +        "type": "number"
        +      },
        +      "proficiency": {
        +        "type": "number"
        +      },
        +      "proficient": {
        +        "type": "boolean"
        +      },
        +      "ranks": {
        +        "type": "number"
        +      },
        +      "rating": {
        +        "description": "Fate: ladder position, -2 (Terrible) to +8 (Legendary); also an FAE approach's rating. Demon Hunters: the trait's die size (4, 6, 8, 10, or 12), or 0 for an unrated Fringe discipline.",
        +        "type": "number"
        +      },
        +      "score": {
        +        "type": "number"
        +      }
        +    },
        +    "type": "object"
        +  },
        +  "type": "array"
        +}
      • addedInput schema / properties / speed
        Added value: +{
        +  "additionalProperties": {},
        +  "properties": {
        +    "base": {
        +      "description": "Walking speed in feet.",
        +      "type": "number"
        +    },
        +    "burrow": {
        +      "type": "number"
        +    },
        +    "climb": {
        +      "type": "number"
        +    },
        +    "fly": {
        +      "type": "number"
        +    },
        +    "swim": {
        +      "type": "number"
        +    }
        +  },
        +  "type": "object"
        +}
      • addedInput schema / properties / spells
        Added value: +{
        +  "items": {
        +    "additionalProperties": {},
        +    "properties": {
        +      "_ref": {
        +        "description": "Mongo `_id` reference (24-character hex string).",
        +        "minLength": 1,
        +        "type": "string"
        +      },
        +      "actions": {
        +        "type": "string"
        +      },
        +      "atWill": {
        +        "description": "Free-cast budget. true = the spell casts without a slot an unlimited number of times (rendered as an 'at will' badge, no use counter); a finite free cast uses maximum/current instead. Absent = an ordinary spell.",
        +        "type": "boolean"
        +      },
        +      "castingAbility": {
        +        "description": "Per-spell spellcasting-ability override (lowercase), stamped at build from the granting block's castingAbility / the player's pick. The sheet computes THIS spell's save DC / attack bonus from it. Absent = the spell uses the character-wide casting ability.",
        +        "enum": [
        +          "strength",
        +          "dexterity",
        +          "constitution",
        +          "intelligence",
        +          "wisdom",
        +          "charisma"
        +        ],
        +        "type": "string"
        +      },
        +      "current": {
        +        "type": "number"
        +      },
        +      "description": {
        +        "type": "string"
        +      },
        +      "detail": {
        +        "type": "string"
        +      },
        +      "level": {
        +        "type": "number"
        +      },
        +      "maximum": {
        +        "type": "number"
        +      },
        +      "name": {
        +        "type": "string"
        +      },
        +      "prepared": {
        +        "type": "boolean"
        +      },
        +      "rank": {
        +        "type": "string"
        +      },
        +      "recovery": {
        +        "description": "Per-rest recovery rows for a finite free-cast counter, stamped from the granting rule's freeCast.recovery whenever the counter is created or grown (creation build and level-up). The vault rest control refills the counter from these when the player declares a Short/Long rest. Absent = the counter doesn't refresh on rest.",
        +        "items": {
        +          "additionalProperties": {},
        +          "properties": {
        +            "count": {
        +              "maximum": 9007199254740991,
        +              "minimum": 0,
        +              "type": "integer"
        +            },
        +            "on": {
        +              "enum": [
        +                "Short",
        +                "Long"
        +              ],
        +              "type": "string"
        +            },
        +            "restoreAll": {
        +              "type": "boolean"
        +            }
        +          },
        +          "type": "object"
        +        },
        +        "type": "array"
        +      },
        +      "school": {
        +        "type": "string"
        +      },
        +      "stock": {
        +        "type": "boolean"
        +      },
        +      "summary": {
        +        "type": "string"
        +      }
        +    },
        +    "type": "object"
        +  },
        +  "type": "array"
        +}
      • addedInput schema / properties / stress
        Added value: +{
        +  "items": {
        +    "additionalProperties": {},
        +    "properties": {
        +      "boxes": {
        +        "items": {
        +          "additionalProperties": {},
        +          "properties": {
        +            "marked": {
        +              "type": "boolean"
        +            },
        +            "value": {
        +              "description": "Shifts this box absorbs. Stated per box, not implied by its position.",
        +              "type": "number"
        +            }
        +          },
        +          "type": "object"
        +        },
        +        "type": "array"
        +      },
        +      "name": {
        +        "description": "Track name — 'Physical Stress' / 'Mental Stress' in Fate Core, 'Stress' in Fate Accelerated.",
        +        "type": "string"
        +      }
        +    },
        +    "type": "object"
        +  },
        +  "type": "array"
        +}
      • addedInput schema / properties / trackables
        Added value: +{
        +  "items": {
        +    "additionalProperties": {},
        +    "properties": {
        +      "_rule": {
        +        "description": "Mongo `_id` reference (24-character hex string).",
        +        "minLength": 1,
        +        "type": "string"
        +      },
        +      "_spell": {
        +        "description": "The Spell this trackable is a free-cast budget for (a spell grant's `freeCast`). Present means 'N casts of this spell without a slot'; the sheet surfaces it on that spell. Absent on every other trackable.",
        +        "minLength": 1,
        +        "type": "string"
        +      },
        +      "current": {
        +        "maximum": 9007199254740991,
        +        "minimum": -9007199254740991,
        +        "type": "integer"
        +      },
        +      "description": {
        +        "type": "string"
        +      },
        +      "maximum": {
        +        "maximum": 9007199254740991,
        +        "minimum": -9007199254740991,
        +        "type": "integer"
        +      },
        +      "name": {
        +        "type": "string"
        +      },
        +      "recovery": {
        +        "items": {
        +          "additionalProperties": {},
        +          "properties": {
        +            "count": {
        +              "maximum": 9007199254740991,
        +              "minimum": 0,
        +              "type": "integer"
        +            },
        +            "on": {
        +              "enum": [
        +                "Short",
        +                "Long"
        +              ],
        +              "type": "string"
        +            },
        +            "restoreAll": {
        +              "type": "boolean"
        +            }
        +          },
        +          "type": "object"
        +        },
        +        "type": "array"
        +      },
        +      "slotLevel": {
        +        "description": "Spell-slot level of this pool (Pact Magic: one pool whose level rises with character level), stamped at build from the granting rule's uses[].slotLevel. The sheet shows it on the trackable row ('Level N'). Absent = an ordinary counter.",
        +        "maximum": 9,
        +        "minimum": 1,
        +        "type": "integer"
        +      },
        +      "type": {
        +        "description": "'number' (counter) or 'checkboxes' (filled boxes). Defaults to 'number'.",
        +        "type": "string"
        +      }
        +    },
        +    "type": "object"
        +  },
        +  "type": "array"
        +}
      • addedInput schema / properties / type
        Added value: +{
        +  "description": "Character type. Free-form per ruleset. Set to 'monster' (lowercase) to mark an authored monster; vault's character list endpoint filters that value out of the default catalog view.",
        +  "type": "string"
        +}
      • addedInput schema / required
        Added value: +[
        +  "name",
        +  "ruleset"
        +]
    • Changedvault_create_item52 fields changed
      • addedInput schema / $schema
        Added value: +"http://json-schema.org/draft-07/schema#"
      • addedInput schema / additionalProperties
        Added value: +{}
      • addedInput schema / properties / _parent
        Added value: +{
        +  "description": "Parent item ObjectId for variant items.",
        +  "minLength": 1,
        +  "type": "string"
        +}
      • addedInput schema / properties / abilityScoreBump
        Added value: +{
        +  "additionalProperties": {},
        +  "properties": {
        +    "options": {
        +      "description": "Alternatives the player picks exactly ONE of (OR).",
        +      "items": {
        +        "additionalProperties": {},
        +        "properties": {
        +          "lines": {
        +            "description": "Lines that ALL apply when this option is chosen (AND).",
        +            "items": {
        +              "additionalProperties": {},
        +              "properties": {
        +                "amount": {
        +                  "description": "How much each chosen ability goes up (usually positive).",
        +                  "type": "number"
        +                },
        +                "count": {
        +                  "description": "How many distinct abilities this line raises.",
        +                  "maximum": 9007199254740991,
        +                  "minimum": 1,
        +                  "type": "integer"
        +                },
        +                "eligible": {
        +                  "description": "Pool to choose from. Empty / absent = any of the six.",
        +                  "items": {
        +                    "enum": [
        +                      "strength",
        +                      "dexterity",
        +                      "constitution",
        +                      "intelligence",
        +                      "wisdom",
        +                      "charisma"
        +                    ],
        +                    "type": "string"
        +                  },
        +                  "type": "array"
        +                },
        +                "max": {
        +                  "description": "Ceiling no chosen score may exceed after the bump (ASI = 20).",
        +                  "maximum": 9007199254740991,
        +                  "minimum": 1,
        +                  "type": "integer"
        +                }
        +              },
        +              "type": "object"
        +            },
        +            "type": "array"
        +          }
        +        },
        +        "type": "object"
        +      },
        +      "type": "array"
        +    }
        +  },
        +  "type": "object"
        +}
      • addedInput schema / properties / abilityScoreSet
        Added value: +{
        +  "items": {
        +    "additionalProperties": {},
        +    "properties": {
        +      "ability": {
        +        "enum": [
        +          "strength",
        +          "dexterity",
        +          "constitution",
        +          "intelligence",
        +          "wisdom",
        +          "charisma"
        +        ],
        +        "type": "string"
        +      },
        +      "value": {
        +        "description": "Score to set the ability to while in effect.",
        +        "maximum": 9007199254740991,
        +        "minimum": 1,
        +        "type": "integer"
        +      }
        +    },
        +    "type": "object"
        +  },
        +  "type": "array"
        +}
      • addedInput schema / properties / actionType
        Added value: +{
        +  "description": "Authoring hint — when set, the character sheet's rule modal shows an 'Add to Actions' button that mints an action row with this `type`.",
        +  "type": "string"
        +}
      • addedInput schema / properties / active
        Added value: +{
        +  "type": "boolean"
        +}
      • addedInput schema / properties / armorCategory
        Added value: +{
        +  "description": "Armor category ('Light', 'Medium', 'Heavy', 'Shield').",
        +  "type": "string"
        +}
      • addedInput schema / properties / armorClass
        Added value: +{
        +  "description": "Base AC value the armor provides.",
        +  "type": "number"
        +}
      • addedInput schema / properties / cost
        Added value: +{
        +  "description": "Cost in gold pieces (max 2 decimal places). Vault enforces non-negativity and precision.",
        +  "minimum": 0,
        +  "type": "number"
        +}
      • addedInput schema / properties / damage
        Added value: +{
        +  "additionalProperties": {},
        +  "properties": {
        +    "appliesTo": {
        +      "enum": [
        +        "melee",
        +        "ranged",
        +        "either"
        +      ],
        +      "type": "string"
        +    },
        +    "area": {
        +      "items": {
        +        "additionalProperties": {},
        +        "properties": {
        +          "shape": {
        +            "enum": [
        +              "cone",
        +              "line",
        +              "sphere",
        +              "cube",
        +              "cylinder",
        +              "emanation",
        +              "radius"
        +            ],
        +            "type": "string"
        +          },
        +          "size": {
        +            "minimum": 0,
        +            "type": "number"
        +          },
        +          "width": {
        +            "minimum": 0,
        +            "type": "number"
        +          }
        +        },
        +        "type": "object"
        +      },
        +      "type": "array"
        +    },
        +    "dice": {
        +      "type": "string"
        +    },
        +    "flat": {
        +      "type": "number"
        +    },
        +    "modifierAbility": {
        +      "enum": [
        +        "strength",
        +        "dexterity",
        +        "constitution",
        +        "intelligence",
        +        "wisdom",
        +        "charisma"
        +      ],
        +      "type": "string"
        +    },
        +    "modifierType": {
        +      "enum": [
        +        "flat",
        +        "proficiency",
        +        "ability"
        +      ],
        +      "type": "string"
        +    },
        +    "onSave": {
        +      "enum": [
        +        "half",
        +        "negates",
        +        "full"
        +      ],
        +      "type": "string"
        +    },
        +    "progression": {
        +      "items": {
        +        "additionalProperties": {},
        +        "properties": {
        +          "dice": {
        +            "type": "string"
        +          },
        +          "flat": {
        +            "type": "number"
        +          },
        +          "level": {
        +            "maximum": 20,
        +            "minimum": 1,
        +            "type": "integer"
        +          }
        +        },
        +        "type": "object"
        +      },
        +      "type": "array"
        +    },
        +    "save": {
        +      "additionalProperties": {},
        +      "properties": {
        +        "ability": {
        +          "enum": [
        +            "none",
        +            "spellcasting",
        +            "attackAttribute",
        +            "strength",
        +            "dexterity",
        +            "constitution",
        +            "intelligence",
        +            "wisdom",
        +            "charisma"
        +          ],
        +          "type": "string"
        +        },
        +        "dcBase": {
        +          "type": "number"
        +        },
        +        "includesProficiency": {
        +          "type": "boolean"
        +        },
        +        "saveType": {
        +          "enum": [
        +            "strength",
        +            "dexterity",
        +            "constitution",
        +            "intelligence",
        +            "wisdom",
        +            "charisma"
        +          ],
        +          "type": "string"
        +        }
        +      },
        +      "type": "object"
        +    },
        +    "scaling": {
        +      "enum": [
        +        "fixed",
        +        "byLevel",
        +        "spellSlot"
        +      ],
        +      "type": "string"
        +    },
        +    "scalingAttribute": {
        +      "type": "string"
        +    },
        +    "slotIncrement": {
        +      "additionalProperties": {},
        +      "properties": {
        +        "dice": {
        +          "type": "string"
        +        },
        +        "flat": {
        +          "type": "number"
        +        },
        +        "targets": {
        +          "maximum": 9007199254740991,
        +          "minimum": 1,
        +          "type": "integer"
        +        }
        +      },
        +      "type": "object"
        +    },
        +    "targets": {
        +      "additionalProperties": {},
        +      "properties": {
        +        "count": {
        +          "maximum": 9007199254740991,
        +          "minimum": 1,
        +          "type": "integer"
        +        }
        +      },
        +      "type": "object"
        +    },
        +    "trigger": {
        +      "enum": [
        +        "passive",
        +        "toggled",
        +        "reaction",
        +        "perRoll",
        +        "resource",
        +        "targetBound"
        +      ],
        +      "type": "string"
        +    },
        +    "types": {
        +      "items": {
        +        "type": "string"
        +      },
        +      "type": "array"
        +    }
        +  },
        +  "type": "object"
        +}
      • addedInput schema / properties / damageDice
        Added value: +{
        +  "description": "Base damage expression (e.g. '1d8').",
        +  "type": "string"
        +}
      • addedInput schema / properties / damageReduction
        Added value: +{
        +  "items": {
        +    "additionalProperties": {},
        +    "properties": {
        +      "amount": {
        +        "additionalProperties": {},
        +        "properties": {
        +          "dice": {
        +            "type": "string"
        +          },
        +          "flat": {
        +            "type": "number"
        +          },
        +          "includesProficiency": {
        +            "type": "boolean"
        +          },
        +          "modifierSource": {
        +            "enum": [
        +              "spellcasting",
        +              "attackAttribute",
        +              "strength",
        +              "dexterity",
        +              "constitution",
        +              "intelligence",
        +              "wisdom",
        +              "charisma"
        +            ],
        +            "type": "string"
        +          }
        +        },
        +        "type": "object"
        +      },
        +      "range": {
        +        "maximum": 9007199254740991,
        +        "minimum": 0,
        +        "type": "integer"
        +      },
        +      "requires": {
        +        "items": {
        +          "additionalProperties": {},
        +          "properties": {
        +            "armorCategories": {
        +              "description": "For 'equipped' + slot:armor: armor category list (Light / Medium / Heavy). OR semantics — match any.",
        +              "items": {
        +                "type": "string"
        +              },
        +              "type": "array"
        +            },
        +            "condition": {
        +              "description": "For 'condition' predicates: the character-state condition to gate on (5e24 named conditions and ongoing-action states).",
        +              "enum": [
        +                "blinded",
        +                "charmed",
        +                "dazed",
        +                "deafened",
        +                "exhaustion",
        +                "frightened",
        +                "grappled",
        +                "incapacitated",
        +                "invisible",
        +                "paralyzed",
        +                "petrified",
        +                "poisoned",
        +                "prone",
        +                "restrained",
        +                "stunned",
        +                "unconscious",
        +                "concentrating",
        +                "grappling",
        +                "dodging",
        +                "hiding",
        +                "raging"
        +              ],
        +              "type": "string"
        +            },
        +            "equipSlot": {
        +              "description": "Body slot the matched weapon must occupy. mainHand / offHand. Resolved via getRequiredSlots so two-handed grips occupy both.",
        +              "enum": [
        +                "mainHand",
        +                "offHand"
        +              ],
        +              "type": "string"
        +            },
        +            "negate": {
        +              "description": "true inverts the predicate — 'while NOT matching' instead of 'while matching'.",
        +              "type": "boolean"
        +            },
        +            "slot": {
        +              "description": "For 'equipped' predicates: the body category to match (armor / shield / weapon).",
        +              "enum": [
        +                "armor",
        +                "shield",
        +                "weapon"
        +              ],
        +              "type": "string"
        +            },
        +            "type": {
        +              "description": "Predicate type. 'equipped' = character-scoped (gates on what's equipped). 'attackingWeapon' = attack-scoped (gates on the current action's source weapon). 'condition' = gates on a character-state condition.",
        +              "enum": [
        +                "equipped",
        +                "attackingWeapon",
        +                "condition"
        +              ],
        +              "type": "string"
        +            },
        +            "weaponProperties": {
        +              "description": "For 'equipped' + slot:weapon OR 'attackingWeapon': weapon-property list. AND semantics — match all.",
        +              "items": {
        +                "type": "string"
        +              },
        +              "type": "array"
        +            }
        +          },
        +          "type": "object"
        +        },
        +        "type": "array"
        +      },
        +      "requiresLogic": {
        +        "enum": [
        +          "and",
        +          "or"
        +        ],
        +        "type": "string"
        +      },
        +      "target": {
        +        "enum": [
        +          "self",
        +          "ally",
        +          "any",
        +          "target",
        +          "enemy"
        +        ],
        +        "type": "string"
        +      },
        +      "trigger": {
        +        "enum": [
        +          "passive",
        +          "toggled",
        +          "reaction",
        +          "perRoll",
        +          "resource",
        +          "targetBound"
        +        ],
        +        "type": "string"
        +      },
        +      "types": {
        +        "items": {
        +          "type": "string"
        +        },
        +        "type": "array"
        +      }
        +    },
        +    "type": "object"
        +  },
        +  "type": "array"
        +}
      • addedInput schema / properties / damageType
        Added value: +{
        +  "description": "Damage types as an array of strings (most items have one type; some have multiples).",
        +  "items": {
        +    "type": "string"
        +  },
        +  "type": "array"
        +}
      • addedInput schema / properties / description
        Added value: +{
        +  "description": "Full item description. Markdown is supported.",
        +  "type": "string"
        +}
      • addedInput schema / properties / diceFloors
        Added value: +{
        +  "items": {
        +    "additionalProperties": {},
        +    "properties": {
        +      "appliesTo": {
        +        "enum": [
        +          "damage",
        +          "damage.melee",
        +          "damage.ranged",
        +          "damage.spell",
        +          "healing"
        +        ],
        +        "type": "string"
        +      },
        +      "floor": {
        +        "maximum": 9007199254740991,
        +        "minimum": 1,
        +        "type": "integer"
        +      },
        +      "requires": {
        +        "items": {
        +          "additionalProperties": {},
        +          "properties": {
        +            "armorCategories": {
        +              "description": "For 'equipped' + slot:armor: armor category list (Light / Medium / Heavy). OR semantics — match any.",
        +              "items": {
        +                "type": "string"
        +              },
        +              "type": "array"
        +            },
        +            "condition": {
        +              "description": "For 'condition' predicates: the character-state condition to gate on (5e24 named conditions and ongoing-action states).",
        +              "enum": [
        +                "blinded",
        +                "charmed",
        +                "dazed",
        +                "deafened",
        +                "exhaustion",
        +                "frightened",
        +                "grappled",
        +                "incapacitated",
        +                "invisible",
        +                "paralyzed",
        +                "petrified",
        +                "poisoned",
        +                "prone",
        +                "restrained",
        +                "stunned",
        +                "unconscious",
        +                "concentrating",
        +                "grappling",
        +                "dodging",
        +                "hiding",
        +                "raging"
        +              ],
        +              "type": "string"
        +            },
        +            "equipSlot": {
        +              "description": "Body slot the matched weapon must occupy. mainHand / offHand. Resolved via getRequiredSlots so two-handed grips occupy both.",
        +              "enum": [
        +                "mainHand",
        +                "offHand"
        +              ],
        +              "type": "string"
        +            },
        +            "negate": {
        +              "description": "true inverts the predicate — 'while NOT matching' instead of 'while matching'.",
        +              "type": "boolean"
        +            },
        +            "slot": {
        +              "description": "For 'equipped' predicates: the body category to match (armor / shield / weapon).",
        +              "enum": [
        +                "armor",
        +                "shield",
        +                "weapon"
        +              ],
        +              "type": "string"
        +            },
        +            "type": {
        +              "description": "Predicate type. 'equipped' = character-scoped (gates on what's equipped). 'attackingWeapon' = attack-scoped (gates on the current action's source weapon). 'condition' = gates on a character-state condition.",
        +              "enum": [
        +                "equipped",
        +                "attackingWeapon",
        +                "condition"
        +              ],
        +              "type": "string"
        +            },
        +            "weaponProperties": {
        +              "description": "For 'equipped' + slot:weapon OR 'attackingWeapon': weapon-property list. AND semantics — match all.",
        +              "items": {
        +                "type": "string"
        +              },
        +              "type": "array"
        +            }
        +          },
        +          "type": "object"
        +        },
        +        "type": "array"
        +      },
        +      "requiresLogic": {
        +        "enum": [
        +          "and",
        +          "or"
        +        ],
        +        "type": "string"
        +      },
        +      "threshold": {
        +        "maximum": 9007199254740991,
        +        "minimum": 1,
        +        "type": "integer"
        +      },
        +      "trigger": {
        +        "enum": [
        +          "passive",
        +          "toggled",
        +          "reaction",
        +          "perRoll",
        +          "resource",
        +          "targetBound"
        +        ],
        +        "type": "string"
        +      }
        +    },
        +    "type": "object"
        +  },
        +  "type": "array"
        +}
      • addedInput schema / properties / diceReplacements
        Added value: +{
        +  "items": {
        +    "additionalProperties": {},
        +    "properties": {
        +      "_target": {
        +        "description": "Mongo `_id` reference (24-character hex string).",
        +        "minLength": 1,
        +        "type": "string"
        +      },
        +      "dice": {
        +        "type": "string"
        +      },
        +      "progression": {
        +        "items": {
        +          "additionalProperties": {},
        +          "properties": {
        +            "dice": {
        +              "type": "string"
        +            },
        +            "level": {
        +              "maximum": 20,
        +              "minimum": 1,
        +              "type": "integer"
        +            }
        +          },
        +          "type": "object"
        +        },
        +        "type": "array"
        +      },
        +      "requires": {
        +        "items": {
        +          "additionalProperties": {},
        +          "properties": {
        +            "armorCategories": {
        +              "description": "For 'equipped' + slot:armor: armor category list (Light / Medium / Heavy). OR semantics — match any.",
        +              "items": {
        +                "type": "string"
        +              },
        +              "type": "array"
        +            },
        +            "condition": {
        +              "description": "For 'condition' predicates: the character-state condition to gate on (5e24 named conditions and ongoing-action states).",
        +              "enum": [
        +                "blinded",
        +                "charmed",
        +                "dazed",
        +                "deafened",
        +                "exhaustion",
        +                "frightened",
        +                "grappled",
        +                "incapacitated",
        +                "invisible",
        +                "paralyzed",
        +                "petrified",
        +                "poisoned",
        +                "prone",
        +                "restrained",
        +                "stunned",
        +                "unconscious",
        +                "concentrating",
        +                "grappling",
        +                "dodging",
        +                "hiding",
        +                "raging"
        +              ],
        +              "type": "string"
        +            },
        +            "equipSlot": {
        +              "description": "Body slot the matched weapon must occupy. mainHand / offHand. Resolved via getRequiredSlots so two-handed grips occupy both.",
        +              "enum": [
        +                "mainHand",
        +                "offHand"
        +              ],
        +              "type": "string"
        +            },
        +            "negate": {
        +              "description": "true inverts the predicate — 'while NOT matching' instead of 'while matching'.",
        +              "type": "boolean"
        +            },
        +            "slot": {
        +              "description": "For 'equipped' predicates: the body category to match (armor / shield / weapon).",
        +              "enum": [
        +                "armor",
        +                "shield",
        +                "weapon"
        +              ],
        +              "type": "string"
        +            },
        +            "type": {
        +              "description": "Predicate type. 'equipped' = character-scoped (gates on what's equipped). 'attackingWeapon' = attack-scoped (gates on the current action's source weapon). 'condition' = gates on a character-state condition.",
        +              "enum": [
        +                "equipped",
        +                "attackingWeapon",
        +                "condition"
        +              ],
        +              "type": "string"
        +            },
        +            "weaponProperties": {
        +              "description": "For 'equipped' + slot:weapon OR 'attackingWeapon': weapon-property list. AND semantics — match all.",
        +              "items": {
        +                "type": "string"
        +              },
        +              "type": "array"
        +            }
        +          },
        +          "type": "object"
        +        },
        +        "type": "array"
        +      },
        +      "requiresLogic": {
        +        "enum": [
        +          "and",
        +          "or"
        +        ],
        +        "type": "string"
        +      }
        +    },
        +    "type": "object"
        +  },
        +  "type": "array"
        +}
      • addedInput schema / properties / duration
        Added value: +{
        +  "additionalProperties": {},
        +  "properties": {
        +    "concentration": {
        +      "type": "boolean"
        +    },
        +    "count": {
        +      "maximum": 9007199254740991,
        +      "minimum": 0,
        +      "type": "integer"
        +    },
        +    "unit": {
        +      "enum": [
        +        "round",
        +        "minute",
        +        "hour",
        +        "day",
        +        "untilShortRest",
        +        "untilLongRest",
        +        "special"
        +      ],
        +      "type": "string"
        +    }
        +  },
        +  "type": "object"
        +}
      • addedInput schema / properties / effect
        Added value: +{
        +  "additionalProperties": {},
        +  "properties": {
        +    "audience": {
        +      "enum": [
        +        "self",
        +        "ally",
        +        "any",
        +        "target",
        +        "enemy"
        +      ],
        +      "type": "string"
        +    },
        +    "conditions": {
        +      "items": {
        +        "additionalProperties": {},
        +        "properties": {
        +          "applyWhen": {
        +            "enum": [
        +              "always",
        +              "onFail",
        +              "onSuccess"
        +            ],
        +            "type": "string"
        +          },
        +          "durationCount": {
        +            "maximum": 9007199254740991,
        +            "minimum": 0,
        +            "type": "integer"
        +          },
        +          "durationUnit": {
        +            "enum": [
        +              "round",
        +              "minute",
        +              "hour",
        +              "day",
        +              "untilShortRest",
        +              "untilLongRest",
        +              "special"
        +            ],
        +            "type": "string"
        +          },
        +          "name": {
        +            "type": "string"
        +          },
        +          "target": {
        +            "enum": [
        +              "self",
        +              "target"
        +            ],
        +            "type": "string"
        +          }
        +        },
        +        "type": "object"
        +      },
        +      "type": "array"
        +    },
        +    "save": {
        +      "additionalProperties": {},
        +      "properties": {
        +        "ability": {
        +          "enum": [
        +            "none",
        +            "spellcasting",
        +            "attackAttribute",
        +            "strength",
        +            "dexterity",
        +            "constitution",
        +            "intelligence",
        +            "wisdom",
        +            "charisma"
        +          ],
        +          "type": "string"
        +        },
        +        "dcBase": {
        +          "type": "number"
        +        },
        +        "includesProficiency": {
        +          "type": "boolean"
        +        },
        +        "saveType": {
        +          "enum": [
        +            "strength",
        +            "dexterity",
        +            "constitution",
        +            "intelligence",
        +            "wisdom",
        +            "charisma"
        +          ],
        +          "type": "string"
        +        }
        +      },
        +      "type": "object"
        +    },
        +    "triggerEvent": {
        +      "enum": [
        +        "onHit",
        +        "onMiss",
        +        "onDamage",
        +        "startOfYourTurn",
        +        "endOfYourTurn",
        +        "startOfTargetTurn",
        +        "endOfTargetTurn"
        +      ],
        +      "type": "string"
        +    }
        +  },
        +  "type": "object"
        +}
      • addedInput schema / properties / equipSlots
        Added value: +{
        +  "description": "Allowed equip slot ids (e.g. 'mainHand', 'offHand', 'body'). Vocabulary is ruleset-specific.",
        +  "items": {
        +    "type": "string"
        +  },
        +  "type": "array"
        +}
      • addedInput schema / properties / forcedMovement
        Added value: +{
        +  "items": {
        +    "additionalProperties": {},
        +    "properties": {
        +      "audience": {
        +        "enum": [
        +          "self",
        +          "ally",
        +          "any",
        +          "target",
        +          "enemy"
        +        ],
        +        "type": "string"
        +      },
        +      "direction": {
        +        "enum": [
        +          "awayFromSelf",
        +          "towardSelf",
        +          "anywhere"
        +        ],
        +        "type": "string"
        +      },
        +      "distance": {
        +        "maximum": 9007199254740991,
        +        "minimum": 0,
        +        "type": "integer"
        +      },
        +      "maxTargetSize": {
        +        "enum": [
        +          "tiny",
        +          "small",
        +          "medium",
        +          "large",
        +          "huge",
        +          "gargantuan"
        +        ],
        +        "type": "string"
        +      },
        +      "requires": {
        +        "items": {
        +          "additionalProperties": {},
        +          "properties": {
        +            "armorCategories": {
        +              "description": "For 'equipped' + slot:armor: armor category list (Light / Medium / Heavy). OR semantics — match any.",
        +              "items": {
        +                "type": "string"
        +              },
        +              "type": "array"
        +            },
        +            "condition": {
        +              "description": "For 'condition' predicates: the character-state condition to gate on (5e24 named conditions and ongoing-action states).",
        +              "enum": [
        +                "blinded",
        +                "charmed",
        +                "dazed",
        +                "deafened",
        +                "exhaustion",
        +                "frightened",
        +                "grappled",
        +                "incapacitated",
        +                "invisible",
        +                "paralyzed",
        +                "petrified",
        +                "poisoned",
        +                "prone",
        +                "restrained",
        +                "stunned",
        +                "unconscious",
        +                "concentrating",
        +                "grappling",
        +                "dodging",
        +                "hiding",
        +                "raging"
        +              ],
        +              "type": "string"
        +            },
        +            "equipSlot": {
        +              "description": "Body slot the matched weapon must occupy. mainHand / offHand. Resolved via getRequiredSlots so two-handed grips occupy both.",
        +              "enum": [
        +                "mainHand",
        +                "offHand"
        +              ],
        +              "type": "string"
        +            },
        +            "negate": {
        +              "description": "true inverts the predicate — 'while NOT matching' instead of 'while matching'.",
        +              "type": "boolean"
        +            },
        +            "slot": {
        +              "description": "For 'equipped' predicates: the body category to match (armor / shield / weapon).",
        +              "enum": [
        +                "armor",
        +                "shield",
        +                "weapon"
        +              ],
        +              "type": "string"
        +            },
        +            "type": {
        +              "description": "Predicate type. 'equipped' = character-scoped (gates on what's equipped). 'attackingWeapon' = attack-scoped (gates on the current action's source weapon). 'condition' = gates on a character-state condition.",
        +              "enum": [
        +                "equipped",
        +                "attackingWeapon",
        +                "condition"
        +              ],
        +              "type": "string"
        +            },
        +            "weaponProperties": {
        +              "description": "For 'equipped' + slot:weapon OR 'attackingWeapon': weapon-property list. AND semantics — match all.",
        +              "items": {
        +                "type": "string"
        +              },
        +              "type": "array"
        +            }
        +          },
        +          "type": "object"
        +        },
        +        "type": "array"
        +      },
        +      "requiresLogic": {
        +        "enum": [
        +          "and",
        +          "or"
        +        ],
        +        "type": "string"
        +      },
        +      "triggerEvent": {
        +        "enum": [
        +          "onHit",
        +          "onMiss",
        +          "onDamage",
        +          "startOfYourTurn",
        +          "endOfYourTurn",
        +          "startOfTargetTurn",
        +          "endOfTargetTurn"
        +        ],
        +        "type": "string"
        +      }
        +    },
        +    "type": "object"
        +  },
        +  "type": "array"
        +}
      • addedInput schema / properties / healing
        Added value: +{
        +  "additionalProperties": {},
        +  "properties": {
        +    "dice": {
        +      "type": "string"
        +    },
        +    "flat": {
        +      "type": "number"
        +    },
        +    "modifierSource": {
        +      "enum": [
        +        "level",
        +        "spellcasting",
        +        "strength",
        +        "dexterity",
        +        "constitution",
        +        "intelligence",
        +        "wisdom",
        +        "charisma"
        +      ],
        +      "type": "string"
        +    },
        +    "progression": {
        +      "items": {
        +        "additionalProperties": {},
        +        "properties": {
        +          "dice": {
        +            "type": "string"
        +          },
        +          "flat": {
        +            "type": "number"
        +          },
        +          "level": {
        +            "maximum": 20,
        +            "minimum": 1,
        +            "type": "integer"
        +          }
        +        },
        +        "type": "object"
        +      },
        +      "type": "array"
        +    },
        +    "scaling": {
        +      "enum": [
        +        "fixed",
        +        "byLevel",
        +        "proficiency",
        +        "spellSlot"
        +      ],
        +      "type": "string"
        +    },
        +    "slotIncrement": {
        +      "additionalProperties": {},
        +      "properties": {
        +        "dice": {
        +          "type": "string"
        +        },
        +        "flat": {
        +          "type": "number"
        +        }
        +      },
        +      "type": "object"
        +    },
        +    "target": {
        +      "enum": [
        +        "self",
        +        "ally",
        +        "any",
        +        "multiple"
        +      ],
        +      "type": "string"
        +    },
        +    "targets": {
        +      "additionalProperties": {},
        +      "properties": {
        +        "count": {
        +          "maximum": 9007199254740991,
        +          "minimum": 1,
        +          "type": "integer"
        +        }
        +      },
        +      "type": "object"
        +    }
        +  },
        +  "type": "object"
        +}
      • addedInput schema / properties / image
        Added value: +{
        +  "additionalProperties": {},
        +  "properties": {
        +    "url": {
        +      "description": "Image URL hosted on Embers Images (or any addressable HTTPS URL).",
        +      "type": "string"
        +    }
        +  },
        +  "type": "object"
        +}
      • addedInput schema / properties / mastery
        Added value: +{
        +  "description": "5e24 weapon mastery name (e.g. 'Topple', 'Vex', 'Slow').",
        +  "type": "string"
        +}
      • addedInput schema / properties / maxDexModifier
        Added value: +{
        +  "description": "Cap on DEX bonus from this armor (medium = 2; heavy = 0 typically).",
        +  "type": "number"
        +}
      • addedInput schema / properties / mechanicsKey
        Added value: +{
        +  "type": "string"
        +}
      • addedInput schema / properties / name
        Added value: +{
        +  "description": "Display name. Required.",
        +  "minLength": 1,
        +  "type": "string"
        +}
      • addedInput schema / properties / ogl
        Added value: +{
        +  "type": "boolean"
        +}
      • addedInput schema / properties / parameters
        Added value: +{
        +  "items": {
        +    "additionalProperties": {},
        +    "properties": {
        +      "label": {
        +        "type": "string"
        +      },
        +      "max": {
        +        "type": "number"
        +      },
        +      "min": {
        +        "type": "number"
        +      },
        +      "name": {
        +        "type": "string"
        +      },
        +      "type": {
        +        "enum": [
        +          "number",
        +          "string",
        +          "enum"
        +        ],
        +        "type": "string"
        +      },
        +      "unit": {
        +        "type": "string"
        +      }
        +    },
        +    "type": "object"
        +  },
        +  "type": "array"
        +}
      • addedInput schema / properties / preparedSpells
        Added value: +{
        +  "additionalProperties": {},
        +  "properties": {
        +    "count": {
        +      "maximum": 9007199254740991,
        +      "minimum": 0,
        +      "type": "integer"
        +    },
        +    "progression": {
        +      "items": {
        +        "additionalProperties": {},
        +        "properties": {
        +          "count": {
        +            "maximum": 9007199254740991,
        +            "minimum": 0,
        +            "type": "integer"
        +          },
        +          "level": {
        +            "maximum": 20,
        +            "minimum": 1,
        +            "type": "integer"
        +          }
        +        },
        +        "type": "object"
        +      },
        +      "type": "array"
        +    }
        +  },
        +  "type": "object"
        +}
      • addedInput schema / properties / prerequisites
        Added value: +{
        +  "items": {
        +    "additionalProperties": {},
        +    "properties": {
        +      "abilities": {
        +        "description": "For abilityScore: ANY listed ability meeting `min` satisfies ('Str or Dex 13+').",
        +        "items": {
        +          "enum": [
        +            "strength",
        +            "dexterity",
        +            "constitution",
        +            "intelligence",
        +            "wisdom",
        +            "charisma"
        +          ],
        +          "type": "string"
        +        },
        +        "type": "array"
        +      },
        +      "category": {
        +        "description": "For rule (filter): matches any held rule in this category.",
        +        "type": "string"
        +      },
        +      "class": {
        +        "description": "For a `level` predicate: a Class rule id that scopes `min` to 'Nth level in that class'. Absent = total character level.",
        +        "minLength": 1,
        +        "type": "string"
        +      },
        +      "min": {
        +        "description": "Numeric minimum — character level (level), class level (class), or ability score (abilityScore).",
        +        "maximum": 9007199254740991,
        +        "minimum": 0,
        +        "type": "integer"
        +      },
        +      "negate": {
        +        "description": "true inverts the predicate — 'must NOT meet this'.",
        +        "type": "boolean"
        +      },
        +      "proficiency": {
        +        "description": "For proficiency: the proficiency name (e.g. 'Martial', 'Stealth').",
        +        "type": "string"
        +      },
        +      "proficiencyType": {
        +        "description": "For proficiency: the family.",
        +        "enum": [
        +          "skill",
        +          "tool",
        +          "weapon",
        +          "armor",
        +          "save",
        +          "language"
        +        ],
        +        "type": "string"
        +      },
        +      "rule": {
        +        "description": "For rule: a specific held Rule id.",
        +        "minLength": 1,
        +        "type": "string"
        +      },
        +      "ruleType": {
        +        "description": "For rule (filter): matches any held rule of this type.",
        +        "type": "string"
        +      },
        +      "spell": {
        +        "description": "For spell: a specific known Spell id.",
        +        "minLength": 1,
        +        "type": "string"
        +      },
        +      "spellList": {
        +        "description": "For spell (filter): knows any spell from this class list.",
        +        "type": "string"
        +      },
        +      "type": {
        +        "description": "Predicate kind: level / abilityScore / rule / spell / proficiency / spellcasting. (A class is required via a `rule` predicate pointing at the class rule.)",
        +        "enum": [
        +          "level",
        +          "abilityScore",
        +          "rule",
        +          "spell",
        +          "proficiency",
        +          "spellcasting"
        +        ],
        +        "type": "string"
        +      }
        +    },
        +    "type": "object"
        +  },
        +  "type": "array"
        +}
      • addedInput schema / properties / prerequisitesLogic
        Added value: +{
        +  "enum": [
        +    "and",
        +    "or"
        +  ],
        +  "type": "string"
        +}
      • addedInput schema / properties / proficiencyChoices
        Added value: +{
        +  "items": {
        +    "additionalProperties": {},
        +    "properties": {
        +      "allowedItems": {
        +        "items": {
        +          "type": "string"
        +        },
        +        "type": "array"
        +      },
        +      "level": {
        +        "enum": [
        +          "proficient",
        +          "expertise"
        +        ],
        +        "type": "string"
        +      },
        +      "mode": {
        +        "enum": [
        +          "specific",
        +          "all"
        +        ],
        +        "type": "string"
        +      },
        +      "progression": {
        +        "items": {
        +          "additionalProperties": {},
        +          "properties": {
        +            "count": {
        +              "maximum": 9007199254740991,
        +              "minimum": 0,
        +              "type": "integer"
        +            },
        +            "level": {
        +              "maximum": 20,
        +              "minimum": 1,
        +              "type": "integer"
        +            }
        +          },
        +          "type": "object"
        +        },
        +        "type": "array"
        +      },
        +      "types": {
        +        "items": {
        +          "enum": [
        +            "skill",
        +            "tool",
        +            "save",
        +            "weapon",
        +            "armor",
        +            "language"
        +          ],
        +          "type": "string"
        +        },
        +        "type": "array"
        +      }
        +    },
        +    "type": "object"
        +  },
        +  "type": "array"
        +}
      • addedInput schema / properties / properties
        Added value: +{
        +  "items": {
        +    "additionalProperties": {},
        +    "properties": {
        +      "ammoType": {
        +        "description": "Ammunition type for the Ammunition property (e.g. 'Arrow', 'Bolt').",
        +        "type": "string"
        +      },
        +      "damage": {
        +        "description": "Per-property damage dice override (e.g. Versatile's two-hand dice).",
        +        "type": "string"
        +      },
        +      "display": {
        +        "description": "Display string overriding the raw name.",
        +        "type": "string"
        +      },
        +      "name": {
        +        "description": "Property identifier (e.g. 'Finesse', 'Versatile', 'Ammunition').",
        +        "type": "string"
        +      },
        +      "range": {
        +        "additionalProperties": {},
        +        "description": "For ranged properties: normal / long reach in feet.",
        +        "properties": {
        +          "long": {
        +            "type": "number"
        +          },
        +          "normal": {
        +            "type": "number"
        +          }
        +        },
        +        "type": "object"
        +      }
        +    },
        +    "type": "object"
        +  },
        +  "type": "array"
        +}
      • addedInput schema / properties / publisher
        Added value: +{
        +  "type": "string"
        +}
      • addedInput schema / properties / recurringDamage
        Added value: +{
        +  "items": {
        +    "additionalProperties": {},
        +    "properties": {
        +      "amount": {
        +        "additionalProperties": {},
        +        "properties": {
        +          "dice": {
        +            "type": "string"
        +          },
        +          "flat": {
        +            "type": "number"
        +          },
        +          "includesProficiency": {
        +            "type": "boolean"
        +          },
        +          "modifierSource": {
        +            "enum": [
        +              "spellcasting",
        +              "attackAttribute",
        +              "strength",
        +              "dexterity",
        +              "constitution",
        +              "intelligence",
        +              "wisdom",
        +              "charisma"
        +            ],
        +            "type": "string"
        +          }
        +        },
        +        "type": "object"
        +      },
        +      "audience": {
        +        "enum": [
        +          "self",
        +          "ally",
        +          "any",
        +          "target",
        +          "enemy"
        +        ],
        +        "type": "string"
        +      },
        +      "durationCount": {
        +        "maximum": 9007199254740991,
        +        "minimum": 0,
        +        "type": "integer"
        +      },
        +      "durationUnit": {
        +        "enum": [
        +          "instantaneous",
        +          "untilStartOfNextTurn",
        +          "untilEndOfNextTurn",
        +          "round",
        +          "minute",
        +          "hour",
        +          "untilShortRest",
        +          "untilLongRest"
        +        ],
        +        "type": "string"
        +      },
        +      "ignoreResistances": {
        +        "type": "boolean"
        +      },
        +      "inheritDamageType": {
        +        "type": "boolean"
        +      },
        +      "range": {
        +        "maximum": 9007199254740991,
        +        "minimum": 0,
        +        "type": "integer"
        +      },
        +      "requires": {
        +        "items": {
        +          "additionalProperties": {},
        +          "properties": {
        +            "armorCategories": {
        +              "description": "For 'equipped' + slot:armor: armor category list (Light / Medium / Heavy). OR semantics — match any.",
        +              "items": {
        +                "type": "string"
        +              },
        +              "type": "array"
        +            },
        +            "condition": {
        +              "description": "For 'condition' predicates: the character-state condition to gate on (5e24 named conditions and ongoing-action states).",
        +              "enum": [
        +                "blinded",
        +                "charmed",
        +                "dazed",
        +                "deafened",
        +                "exhaustion",
        +                "frightened",
        +                "grappled",
        +                "incapacitated",
        +                "invisible",
        +                "paralyzed",
        +                "petrified",
        +                "poisoned",
        +                "prone",
        +                "restrained",
        +                "stunned",
        +                "unconscious",
        +                "concentrating",
        +                "grappling",
        +                "dodging",
        +                "hiding",
        +                "raging"
        +              ],
        +              "type": "string"
        +            },
        +            "equipSlot": {
        +              "description": "Body slot the matched weapon must occupy. mainHand / offHand. Resolved via getRequiredSlots so two-handed grips occupy both.",
        +              "enum": [
        +                "mainHand",
        +                "offHand"
        +              ],
        +              "type": "string"
        +            },
        +            "negate": {
        +              "description": "true inverts the predicate — 'while NOT matching' instead of 'while matching'.",
        +              "type": "boolean"
        +            },
        +            "slot": {
        +              "description": "For 'equipped' predicates: the body category to match (armor / shield / weapon).",
        +              "enum": [
        +                "armor",
        +                "shield",
        +                "weapon"
        +              ],
        +              "type": "string"
        +            },
        +            "type": {
        +              "description": "Predicate type. 'equipped' = character-scoped (gates on what's equipped). 'attackingWeapon' = attack-scoped (gates on the current action's source weapon). 'condition' = gates on a character-state condition.",
        +              "enum": [
        +                "equipped",
        +                "attackingWeapon",
        +                "condition"
        +              ],
        +              "type": "string"
        +            },
        +            "weaponProperties": {
        +              "description": "For 'equipped' + slot:weapon OR 'attackingWeapon': weapon-property list. AND semantics — match all.",
        +              "items": {
        +                "type": "string"
        +              },
        +              "type": "array"
        +            }
        +          },
        +          "type": "object"
        +        },
        +        "type": "array"
        +      },
        +      "requiresLogic": {
        +        "enum": [
        +          "and",
        +          "or"
        +        ],
        +        "type": "string"
        +      },
        +      "triggerEvent": {
        +        "enum": [
        +          "startOfYourTurn",
        +          "endOfYourTurn",
        +          "startOfTargetTurn",
        +          "endOfTargetTurn",
        +          "whenTargetEntersArea",
        +          "onHit",
        +          "onMiss",
        +          "onDamage"
        +        ],
        +        "type": "string"
        +      },
        +      "types": {
        +        "items": {
        +          "type": "string"
        +        },
        +        "type": "array"
        +      }
        +    },
        +    "type": "object"
        +  },
        +  "type": "array"
        +}
      • addedInput schema / properties / resistances
        Added value: +{
        +  "items": {
        +    "additionalProperties": {},
        +    "properties": {
        +      "mode": {
        +        "enum": [
        +          "resistance",
        +          "immunity",
        +          "vulnerability"
        +        ],
        +        "type": "string"
        +      },
        +      "range": {
        +        "description": "Aura radius in feet for ally/any-targeted resistances (Warding Aura's 10 ft.). Absent = self-only.",
        +        "maximum": 9007199254740991,
        +        "minimum": 0,
        +        "type": "integer"
        +      },
        +      "target": {
        +        "description": "Who the resistance protects — mirrors damageReduction's target/range pair. Absent = self.",
        +        "enum": [
        +          "self",
        +          "ally",
        +          "any",
        +          "target",
        +          "enemy"
        +        ],
        +        "type": "string"
        +      },
        +      "trigger": {
        +        "enum": [
        +          "passive",
        +          "toggled",
        +          "reaction",
        +          "perRoll",
        +          "resource",
        +          "targetBound"
        +        ],
        +        "type": "string"
        +      },
        +      "types": {
        +        "items": {
        +          "type": "string"
        +        },
        +        "type": "array"
        +      }
        +    },
        +    "type": "object"
        +  },
        +  "type": "array"
        +}
      • addedInput schema / properties / rollMods
        Added value: +{
        +  "items": {
        +    "additionalProperties": {},
        +    "properties": {
        +      "audience": {
        +        "enum": [
        +          "self",
        +          "ally",
        +          "any",
        +          "target",
        +          "enemy"
        +        ],
        +        "type": "string"
        +      },
        +      "consumeOnUse": {
        +        "type": "boolean"
        +      },
        +      "durationCount": {
        +        "maximum": 9007199254740991,
        +        "minimum": 0,
        +        "type": "integer"
        +      },
        +      "durationUnit": {
        +        "enum": [
        +          "instantaneous",
        +          "untilStartOfNextTurn",
        +          "untilEndOfNextTurn",
        +          "round",
        +          "minute",
        +          "hour",
        +          "untilShortRest",
        +          "untilLongRest"
        +        ],
        +        "type": "string"
        +      },
        +      "mode": {
        +        "enum": [
        +          "advantage",
        +          "disadvantage"
        +        ],
        +        "type": "string"
        +      },
        +      "range": {
        +        "maximum": 9007199254740991,
        +        "minimum": 0,
        +        "type": "integer"
        +      },
        +      "requires": {
        +        "items": {
        +          "additionalProperties": {},
        +          "properties": {
        +            "armorCategories": {
        +              "description": "For 'equipped' + slot:armor: armor category list (Light / Medium / Heavy). OR semantics — match any.",
        +              "items": {
        +                "type": "string"
        +              },
        +              "type": "array"
        +            },
        +            "condition": {
        +              "description": "For 'condition' predicates: the character-state condition to gate on (5e24 named conditions and ongoing-action states).",
        +              "enum": [
        +                "blinded",
        +                "charmed",
        +                "dazed",
        +                "deafened",
        +                "exhaustion",
        +                "frightened",
        +                "grappled",
        +                "incapacitated",
        +                "invisible",
        +                "paralyzed",
        +                "petrified",
        +                "poisoned",
        +                "prone",
        +                "restrained",
        +                "stunned",
        +                "unconscious",
        +                "concentrating",
        +                "grappling",
        +                "dodging",
        +                "hiding",
        +                "raging"
        +              ],
        +              "type": "string"
        +            },
        +            "equipSlot": {
        +              "description": "Body slot the matched weapon must occupy. mainHand / offHand. Resolved via getRequiredSlots so two-handed grips occupy both.",
        +              "enum": [
        +                "mainHand",
        +                "offHand"
        +              ],
        +              "type": "string"
        +            },
        +            "negate": {
        +              "description": "true inverts the predicate — 'while NOT matching' instead of 'while matching'.",
        +              "type": "boolean"
        +            },
        +            "slot": {
        +              "description": "For 'equipped' predicates: the body category to match (armor / shield / weapon).",
        +              "enum": [
        +                "armor",
        +                "shield",
        +                "weapon"
        +              ],
        +              "type": "string"
        +            },
        +            "type": {
        +              "description": "Predicate type. 'equipped' = character-scoped (gates on what's equipped). 'attackingWeapon' = attack-scoped (gates on the current action's source weapon). 'condition' = gates on a character-state condition.",
        +              "enum": [
        +                "equipped",
        +                "attackingWeapon",
        +                "condition"
        +              ],
        +              "type": "string"
        +            },
        +            "weaponProperties": {
        +              "description": "For 'equipped' + slot:weapon OR 'attackingWeapon': weapon-property list. AND semantics — match all.",
        +              "items": {
        +                "type": "string"
        +              },
        +              "type": "array"
        +            }
        +          },
        +          "type": "object"
        +        },
        +        "type": "array"
        +      },
        +      "requiresLogic": {
        +        "enum": [
        +          "and",
        +          "or"
        +        ],
        +        "type": "string"
        +      },
        +      "rollScope": {
        +        "enum": [
        +          "attack",
        +          "save",
        +          "abilityCheck",
        +          "skillCheck"
        +        ],
        +        "type": "string"
        +      },
        +      "trigger": {
        +        "enum": [
        +          "passive",
        +          "toggled",
        +          "reaction",
        +          "perRoll",
        +          "resource",
        +          "targetBound"
        +        ],
        +        "type": "string"
        +      },
        +      "triggerEvent": {
        +        "enum": [
        +          "onHit",
        +          "onMiss",
        +          "onDamage",
        +          "startOfYourTurn",
        +          "endOfYourTurn",
        +          "startOfTargetTurn",
        +          "endOfTargetTurn"
        +        ],
        +        "type": "string"
        +      }
        +    },
        +    "type": "object"
        +  },
        +  "type": "array"
        +}
      • addedInput schema / properties / ruleChoice
        Added value: +{
        +  "additionalProperties": {},
        +  "properties": {
        +    "allowedCategories": {
        +      "items": {
        +        "type": "string"
        +      },
        +      "type": "array"
        +    },
        +    "allowedRuleParameters": {
        +      "additionalProperties": {
        +        "additionalProperties": {},
        +        "properties": {
        +          "damageType": {
        +            "type": "string"
        +          },
        +          "number": {
        +            "maximum": 9007199254740991,
        +            "minimum": 0,
        +            "type": "integer"
        +          },
        +          "range": {
        +            "maximum": 9007199254740991,
        +            "minimum": 0,
        +            "type": "integer"
        +          },
        +          "speed": {
        +            "maximum": 9007199254740991,
        +            "minimum": 0,
        +            "type": "integer"
        +          }
        +        },
        +        "type": "object"
        +      },
        +      "propertyNames": {
        +        "type": "string"
        +      },
        +      "type": "object"
        +    },
        +    "allowedRules": {
        +      "items": {
        +        "description": "Mongo `_id` reference (24-character hex string).",
        +        "minLength": 1,
        +        "type": "string"
        +      },
        +      "type": "array"
        +    },
        +    "allowedTypes": {
        +      "items": {
        +        "type": "string"
        +      },
        +      "type": "array"
        +    },
        +    "count": {
        +      "maximum": 9007199254740991,
        +      "minimum": 0,
        +      "type": "integer"
        +    },
        +    "label": {
        +      "type": "string"
        +    },
        +    "mode": {
        +      "enum": [
        +        "filter",
        +        "specific"
        +      ],
        +      "type": "string"
        +    },
        +    "progression": {
        +      "items": {
        +        "additionalProperties": {},
        +        "properties": {
        +          "count": {
        +            "maximum": 9007199254740991,
        +            "minimum": 0,
        +            "type": "integer"
        +          },
        +          "level": {
        +            "maximum": 20,
        +            "minimum": 1,
        +            "type": "integer"
        +          }
        +        },
        +        "type": "object"
        +      },
        +      "type": "array"
        +    },
        +    "scaling": {
        +      "enum": [
        +        "fixed",
        +        "byLevel"
        +      ],
        +      "type": "string"
        +    }
        +  },
        +  "type": "object"
        +}
      • addedInput schema / properties / ruleset
        Added value: +{
        +  "description": "Ruleset code (e.g. '5th Edition', '5e24', 'PFRPG', 'Savage Worlds').",
        +  "type": "string"
        +}
      • addedInput schema / properties / source
        Added value: +{
        +  "type": "string"
        +}
      • addedInput schema / properties / spellChoices
        Added value: +{
        +  "items": {
        +    "additionalProperties": {},
        +    "properties": {
        +      "allowedCategories": {
        +        "items": {
        +          "type": "string"
        +        },
        +        "type": "array"
        +      },
        +      "allowedSchools": {
        +        "items": {
        +          "type": "string"
        +        },
        +        "type": "array"
        +      },
        +      "allowedSpells": {
        +        "items": {
        +          "description": "Mongo `_id` reference (24-character hex string).",
        +          "minLength": 1,
        +          "type": "string"
        +        },
        +        "type": "array"
        +      },
        +      "castingAbility": {
        +        "enum": [
        +          "strength",
        +          "dexterity",
        +          "constitution",
        +          "intelligence",
        +          "wisdom",
        +          "charisma"
        +        ],
        +        "type": "string"
        +      },
        +      "castingAbilityOptions": {
        +        "items": {
        +          "enum": [
        +            "strength",
        +            "dexterity",
        +            "constitution",
        +            "intelligence",
        +            "wisdom",
        +            "charisma"
        +          ],
        +          "type": "string"
        +        },
        +        "type": "array"
        +      },
        +      "freeCast": {
        +        "additionalProperties": {},
        +        "properties": {
        +          "atWill": {
        +            "type": "boolean"
        +          },
        +          "count": {
        +            "maximum": 9007199254740991,
        +            "minimum": 0,
        +            "type": "integer"
        +          },
        +          "progression": {
        +            "items": {
        +              "additionalProperties": {},
        +              "properties": {
        +                "count": {
        +                  "maximum": 9007199254740991,
        +                  "minimum": 0,
        +                  "type": "integer"
        +                },
        +                "level": {
        +                  "maximum": 20,
        +                  "minimum": 1,
        +                  "type": "integer"
        +                }
        +              },
        +              "type": "object"
        +            },
        +            "type": "array"
        +          },
        +          "recovery": {
        +            "items": {
        +              "additionalProperties": {},
        +              "properties": {
        +                "count": {
        +                  "maximum": 9007199254740991,
        +                  "minimum": 0,
        +                  "type": "integer"
        +                },
        +                "on": {
        +                  "enum": [
        +                    "Short",
        +                    "Long"
        +                  ],
        +                  "type": "string"
        +                },
        +                "restoreAll": {
        +                  "type": "boolean"
        +                }
        +              },
        +              "type": "object"
        +            },
        +            "type": "array"
        +          }
        +        },
        +        "type": "object"
        +      },
        +      "label": {
        +        "type": "string"
        +      },
        +      "maxLevel": {
        +        "maximum": 9,
        +        "minimum": 0,
        +        "type": "integer"
        +      },
        +      "minLevel": {
        +        "maximum": 9,
        +        "minimum": 0,
        +        "type": "integer"
        +      },
        +      "mode": {
        +        "enum": [
        +          "filter",
        +          "specific"
        +        ],
        +        "type": "string"
        +      },
        +      "prepared": {
        +        "type": "boolean"
        +      },
        +      "progression": {
        +        "items": {
        +          "additionalProperties": {},
        +          "properties": {
        +            "count": {
        +              "maximum": 9007199254740991,
        +              "minimum": 0,
        +              "type": "integer"
        +            },
        +            "level": {
        +              "maximum": 20,
        +              "minimum": 1,
        +              "type": "integer"
        +            }
        +          },
        +          "type": "object"
        +        },
        +        "type": "array"
        +      }
        +    },
        +    "type": "object"
        +  },
        +  "type": "array"
        +}
      • addedInput schema / properties / spellListChoices
        Added value: +{
        +  "items": {
        +    "additionalProperties": {},
        +    "properties": {
        +      "allowedCategories": {
        +        "items": {
        +          "type": "string"
        +        },
        +        "type": "array"
        +      },
        +      "castingAbility": {
        +        "enum": [
        +          "strength",
        +          "dexterity",
        +          "constitution",
        +          "intelligence",
        +          "wisdom",
        +          "charisma"
        +        ],
        +        "type": "string"
        +      },
        +      "castingAbilityOptions": {
        +        "items": {
        +          "enum": [
        +            "strength",
        +            "dexterity",
        +            "constitution",
        +            "intelligence",
        +            "wisdom",
        +            "charisma"
        +          ],
        +          "type": "string"
        +        },
        +        "type": "array"
        +      },
        +      "label": {
        +        "type": "string"
        +      },
        +      "picks": {
        +        "items": {
        +          "additionalProperties": {},
        +          "properties": {
        +            "count": {
        +              "maximum": 9007199254740991,
        +              "minimum": 0,
        +              "type": "integer"
        +            },
        +            "freeCast": {
        +              "additionalProperties": {},
        +              "properties": {
        +                "atWill": {
        +                  "type": "boolean"
        +                },
        +                "count": {
        +                  "maximum": 9007199254740991,
        +                  "minimum": 0,
        +                  "type": "integer"
        +                },
        +                "progression": {
        +                  "items": {
        +                    "additionalProperties": {},
        +                    "properties": {
        +                      "count": {
        +                        "maximum": 9007199254740991,
        +                        "minimum": 0,
        +                        "type": "integer"
        +                      },
        +                      "level": {
        +                        "maximum": 20,
        +                        "minimum": 1,
        +                        "type": "integer"
        +                      }
        +                    },
        +                    "type": "object"
        +                  },
        +                  "type": "array"
        +                },
        +                "recovery": {
        +                  "items": {
        +                    "additionalProperties": {},
        +                    "properties": {
        +                      "count": {
        +                        "maximum": 9007199254740991,
        +                        "minimum": 0,
        +                        "type": "integer"
        +                      },
        +                      "on": {
        +                        "enum": [
        +                          "Short",
        +                          "Long"
        +                        ],
        +                        "type": "string"
        +                      },
        +                      "restoreAll": {
        +                        "type": "boolean"
        +                      }
        +                    },
        +                    "type": "object"
        +                  },
        +                  "type": "array"
        +                }
        +              },
        +              "type": "object"
        +            },
        +            "label": {
        +              "type": "string"
        +            },
        +            "maxLevel": {
        +              "maximum": 9,
        +              "minimum": 0,
        +              "type": "integer"
        +            },
        +            "minLevel": {
        +              "maximum": 9,
        +              "minimum": 0,
        +              "type": "integer"
        +            }
        +          },
        +          "type": "object"
        +        },
        +        "type": "array"
        +      },
        +      "prepared": {
        +        "type": "boolean"
        +      }
        +    },
        +    "type": "object"
        +  },
        +  "type": "array"
        +}
      • addedInput schema / properties / statBonuses
        Added value: +{
        +  "items": {
        +    "additionalProperties": {},
        +    "properties": {
        +      "attribute": {
        +        "description": "For valueType: 'attribute' — which ability's modifier to use.",
        +        "type": "string"
        +      },
        +      "audience": {
        +        "description": "Who the bonus contributes to. Absent = self.",
        +        "enum": [
        +          "self",
        +          "ally",
        +          "any",
        +          "target",
        +          "enemy"
        +        ],
        +        "type": "string"
        +      },
        +      "dice": {
        +        "description": "For valueType: 'dice' — dice expression (e.g. '1d4').",
        +        "type": "string"
        +      },
        +      "durationCount": {
        +        "description": "Numeric count paired with durationUnit (e.g. count: 3, unit: 'round').",
        +        "maximum": 9007199254740991,
        +        "minimum": 0,
        +        "type": "integer"
        +      },
        +      "durationUnit": {
        +        "description": "How long the bonus persists once fired. Only meaningful for event-driven bonuses.",
        +        "enum": [
        +          "instantaneous",
        +          "untilStartOfNextTurn",
        +          "untilEndOfNextTurn",
        +          "round",
        +          "minute",
        +          "hour",
        +          "untilShortRest",
        +          "untilLongRest"
        +        ],
        +        "type": "string"
        +      },
        +      "fixed": {
        +        "description": "For valueType: 'fixed' — the literal numeric contribution.",
        +        "type": "number"
        +      },
        +      "progression": {
        +        "description": "For valueType: 'byLevel' — per-level rows; walker picks the row with level <= current level.",
        +        "items": {
        +          "additionalProperties": {},
        +          "properties": {
        +            "dice": {
        +              "type": "string"
        +            },
        +            "flat": {
        +              "type": "number"
        +            },
        +            "level": {
        +              "maximum": 20,
        +              "minimum": 1,
        +              "type": "integer"
        +            }
        +          },
        +          "type": "object"
        +        },
        +        "type": "array"
        +      },
        +      "range": {
        +        "description": "Aura radius in feet for ally/any-audience bonuses (Aura of Protection's 10 ft.). Absent = no range filter.",
        +        "maximum": 9007199254740991,
        +        "minimum": 0,
        +        "type": "integer"
        +      },
        +      "requires": {
        +        "description": "Optional predicate list that gates this bonus. Absent / empty = always-on.",
        +        "items": {
        +          "additionalProperties": {},
        +          "properties": {
        +            "armorCategories": {
        +              "description": "For 'equipped' + slot:armor: armor category list (Light / Medium / Heavy). OR semantics — match any.",
        +              "items": {
        +                "type": "string"
        +              },
        +              "type": "array"
        +            },
        +            "condition": {
        +              "description": "For 'condition' predicates: the character-state condition to gate on (5e24 named conditions and ongoing-action states).",
        +              "enum": [
        +                "blinded",
        +                "charmed",
        +                "dazed",
        +                "deafened",
        +                "exhaustion",
        +                "frightened",
        +                "grappled",
        +                "incapacitated",
        +                "invisible",
        +                "paralyzed",
        +                "petrified",
        +                "poisoned",
        +                "prone",
        +                "restrained",
        +                "stunned",
        +                "unconscious",
        +                "concentrating",
        +                "grappling",
        +                "dodging",
        +                "hiding",
        +                "raging"
        +              ],
        +              "type": "string"
        +            },
        +            "equipSlot": {
        +              "description": "Body slot the matched weapon must occupy. mainHand / offHand. Resolved via getRequiredSlots so two-handed grips occupy both.",
        +              "enum": [
        +                "mainHand",
        +                "offHand"
        +              ],
        +              "type": "string"
        +            },
        +            "negate": {
        +              "description": "true inverts the predicate — 'while NOT matching' instead of 'while matching'.",
        +              "type": "boolean"
        +            },
        +            "slot": {
        +              "description": "For 'equipped' predicates: the body category to match (armor / shield / weapon).",
        +              "enum": [
        +                "armor",
        +                "shield",
        +                "weapon"
        +              ],
        +              "type": "string"
        +            },
        +            "type": {
        +              "description": "Predicate type. 'equipped' = character-scoped (gates on what's equipped). 'attackingWeapon' = attack-scoped (gates on the current action's source weapon). 'condition' = gates on a character-state condition.",
        +              "enum": [
        +                "equipped",
        +                "attackingWeapon",
        +                "condition"
        +              ],
        +              "type": "string"
        +            },
        +            "weaponProperties": {
        +              "description": "For 'equipped' + slot:weapon OR 'attackingWeapon': weapon-property list. AND semantics — match all.",
        +              "items": {
        +                "type": "string"
        +              },
        +              "type": "array"
        +            }
        +          },
        +          "type": "object"
        +        },
        +        "type": "array"
        +      },
        +      "requiresLogic": {
        +        "description": "How `requires` predicates compose. 'and' (default) = ALL must hold. 'or' = ANY one is sufficient.",
        +        "enum": [
        +          "and",
        +          "or"
        +        ],
        +        "type": "string"
        +      },
        +      "target": {
        +        "description": "Stat the bonus contributes to (e.g. 'skills.Acrobatics.misc', 'attributes.strength.misc').",
        +        "type": "string"
        +      },
        +      "trigger": {
        +        "description": "Action-economy / cost shape of the bonus. passive / toggled / reaction / perRoll / resource / targetBound.",
        +        "enum": [
        +          "passive",
        +          "toggled",
        +          "reaction",
        +          "perRoll",
        +          "resource",
        +          "targetBound"
        +        ],
        +        "type": "string"
        +      },
        +      "triggerEvent": {
        +        "description": "Game-time event that fires the bonus (onHit / onDamage / startOfYourTurn / etc.). Absent = not event-driven (passive walker contributes whenever `requires` holds).",
        +        "enum": [
        +          "onHit",
        +          "onMiss",
        +          "onDamage",
        +          "startOfYourTurn",
        +          "endOfYourTurn",
        +          "startOfTargetTurn",
        +          "endOfTargetTurn"
        +        ],
        +        "type": "string"
        +      },
        +      "types": {
        +        "description": "Damage type tags for damage.* targets. No-op for non-damage targets.",
        +        "items": {
        +          "type": "string"
        +        },
        +        "type": "array"
        +      },
        +      "valueType": {
        +        "description": "How the contribution is computed. 'fixed' uses `fixed`; 'attribute' uses the mod of `attribute`; 'attackAttribute' uses the action's attack-roll ability (per-attack only); others scale by level/PB/dice.",
        +        "enum": [
        +          "fixed",
        +          "attribute",
        +          "proficiency",
        +          "level",
        +          "halfLevel",
        +          "dice",
        +          "byLevel",
        +          "attackAttribute"
        +        ],
        +        "type": "string"
        +      }
        +    },
        +    "type": "object"
        +  },
        +  "type": "array"
        +}
      • addedInput schema / properties / stealthDisadvantage
        Added value: +{
        +  "type": "boolean"
        +}
      • addedInput schema / properties / strengthRequirement
        Added value: +{
        +  "type": "number"
        +}
      • addedInput schema / properties / summary
        Added value: +{
        +  "description": "Short one-line summary.",
        +  "type": "string"
        +}
      • addedInput schema / properties / type
        Added value: +{
        +  "description": "Item type. Required.",
        +  "minLength": 1,
        +  "type": "string"
        +}
      • addedInput schema / properties / uses
        Added value: +{
        +  "items": {
        +    "additionalProperties": {},
        +    "properties": {
        +      "count": {
        +        "maximum": 9007199254740991,
        +        "minimum": 0,
        +        "type": "integer"
        +      },
        +      "mode": {
        +        "enum": [
        +          "fixed",
        +          "byLevel",
        +          "proficiency"
        +        ],
        +        "type": "string"
        +      },
        +      "name": {
        +        "type": "string"
        +      },
        +      "progression": {
        +        "items": {
        +          "additionalProperties": {},
        +          "properties": {
        +            "count": {
        +              "maximum": 9007199254740991,
        +              "minimum": 0,
        +              "type": "integer"
        +            },
        +            "countAbility": {
        +              "enum": [
        +                "strength",
        +                "dexterity",
        +                "constitution",
        +                "intelligence",
        +                "wisdom",
        +                "charisma"
        +              ],
        +              "type": "string"
        +            },
        +            "countSource": {
        +              "enum": [
        +                "fixed",
        +                "proficiency",
        +                "abilityMod"
        +              ],
        +              "type": "string"
        +            },
        +            "level": {
        +              "maximum": 20,
        +              "minimum": 1,
        +              "type": "integer"
        +            },
        +            "slotLevel": {
        +              "maximum": 9,
        +              "minimum": 1,
        +              "type": "integer"
        +            }
        +          },
        +          "type": "object"
        +        },
        +        "type": "array"
        +      },
        +      "recovery": {
        +        "items": {
        +          "additionalProperties": {},
        +          "properties": {
        +            "count": {
        +              "maximum": 9007199254740991,
        +              "minimum": 0,
        +              "type": "integer"
        +            },
        +            "on": {
        +              "enum": [
        +                "Short",
        +                "Long"
        +              ],
        +              "type": "string"
        +            },
        +            "restoreAll": {
        +              "type": "boolean"
        +            }
        +          },
        +          "type": "object"
        +        },
        +        "type": "array"
        +      },
        +      "rest": {
        +        "enum": [
        +          "Short",
        +          "Long"
        +        ],
        +        "type": "string"
        +      },
        +      "slotLevel": {
        +        "maximum": 9,
        +        "minimum": 1,
        +        "type": "integer"
        +      }
        +    },
        +    "type": "object"
        +  },
        +  "type": "array"
        +}
      • addedInput schema / properties / weaponType
        Added value: +{
        +  "description": "Weapon category ('Simple Melee', 'Martial Ranged', etc.).",
        +  "type": "string"
        +}
      • addedInput schema / properties / weight
        Added value: +{
        +  "type": "number"
        +}
      • addedInput schema / required
        Added value: +[
        +  "name",
        +  "type"
        +]
    • Changedvault_create_rule69 fields changed
      • addedInput schema / $schema
        Added value: +"http://json-schema.org/draft-07/schema#"
      • addedInput schema / additionalProperties
        Added value: +{}
      • addedInput schema / properties / _parent
        Added value: +{
        +  "description": "Mongo `_id` reference (24-character hex string).",
        +  "minLength": 1,
        +  "type": "string"
        +}
      • addedInput schema / properties / abilities
        Added value: +{
        +  "items": {
        +    "additionalProperties": {},
        +    "properties": {
        +      "_rule": {
        +        "description": "Granted Rule ObjectId.",
        +        "minLength": 1,
        +        "type": "string"
        +      },
        +      "level": {
        +        "maximum": 20,
        +        "minimum": 1,
        +        "type": "integer"
        +      },
        +      "parameterValues": {
        +        "additionalProperties": {},
        +        "properties": {
        +          "damageType": {
        +            "type": "string"
        +          },
        +          "number": {
        +            "maximum": 9007199254740991,
        +            "minimum": 0,
        +            "type": "integer"
        +          },
        +          "range": {
        +            "maximum": 9007199254740991,
        +            "minimum": 0,
        +            "type": "integer"
        +          },
        +          "speed": {
        +            "maximum": 9007199254740991,
        +            "minimum": 0,
        +            "type": "integer"
        +          }
        +        },
        +        "type": "object"
        +      }
        +    },
        +    "type": "object"
        +  },
        +  "type": "array"
        +}
      • addedInput schema / properties / abilityScoreBump
        Added value: +{
        +  "additionalProperties": {},
        +  "properties": {
        +    "options": {
        +      "description": "Alternatives the player picks exactly ONE of (OR).",
        +      "items": {
        +        "additionalProperties": {},
        +        "properties": {
        +          "lines": {
        +            "description": "Lines that ALL apply when this option is chosen (AND).",
        +            "items": {
        +              "additionalProperties": {},
        +              "properties": {
        +                "amount": {
        +                  "description": "How much each chosen ability goes up (usually positive).",
        +                  "type": "number"
        +                },
        +                "count": {
        +                  "description": "How many distinct abilities this line raises.",
        +                  "maximum": 9007199254740991,
        +                  "minimum": 1,
        +                  "type": "integer"
        +                },
        +                "eligible": {
        +                  "description": "Pool to choose from. Empty / absent = any of the six.",
        +                  "items": {
        +                    "enum": [
        +                      "strength",
        +                      "dexterity",
        +                      "constitution",
        +                      "intelligence",
        +                      "wisdom",
        +                      "charisma"
        +                    ],
        +                    "type": "string"
        +                  },
        +                  "type": "array"
        +                },
        +                "max": {
        +                  "description": "Ceiling no chosen score may exceed after the bump (ASI = 20).",
        +                  "maximum": 9007199254740991,
        +                  "minimum": 1,
        +                  "type": "integer"
        +                }
        +              },
        +              "type": "object"
        +            },
        +            "type": "array"
        +          }
        +        },
        +        "type": "object"
        +      },
        +      "type": "array"
        +    }
        +  },
        +  "type": "object"
        +}
      • addedInput schema / properties / abilityScoreSet
        Added value: +{
        +  "items": {
        +    "additionalProperties": {},
        +    "properties": {
        +      "ability": {
        +        "enum": [
        +          "strength",
        +          "dexterity",
        +          "constitution",
        +          "intelligence",
        +          "wisdom",
        +          "charisma"
        +        ],
        +        "type": "string"
        +      },
        +      "value": {
        +        "description": "Score to set the ability to while in effect.",
        +        "maximum": 9007199254740991,
        +        "minimum": 1,
        +        "type": "integer"
        +      }
        +    },
        +    "type": "object"
        +  },
        +  "type": "array"
        +}
      • addedInput schema / properties / abilityScores
        Added value: +{
        +  "items": {
        +    "type": "string"
        +  },
        +  "type": "array"
        +}
      • addedInput schema / properties / actionEconomy
        Added value: +{
        +  "description": "What invoking the ability costs on a turn: 'Action', 'Bonus Action', or 'Reaction'. Distinct from the mechanics actionType (a kind-of-action label). Absent = the ability takes the action.",
        +  "type": "string"
        +}
      • addedInput schema / properties / actionType
        Added value: +{
        +  "description": "Authoring hint — when set, the character sheet's rule modal shows an 'Add to Actions' button that mints an action row with this `type`.",
        +  "type": "string"
        +}
      • addedInput schema / properties / actions
        Added value: +{
        +  "description": "PF Playtest action-economy marker (F/1/2/3/R).",
        +  "type": "string"
        +}
      • addedInput schema / properties / active
        Added value: +{
        +  "type": "boolean"
        +}
      • addedInput schema / properties / age
        Added value: +{
        +  "type": "string"
        +}
      • addedInput schema / properties / armorTraining
        Added value: +{
        +  "items": {
        +    "type": "string"
        +  },
        +  "type": "array"
        +}
      • addedInput schema / properties / casterProgression
        Added value: +{
        +  "description": "How this class contributes to the combined multiclass spell-slot pool: full casters count every level, half/third round up, 'pact' (Pact Magic) keeps its own pool and never joins. Authorable on a base class or a subclass (a third-caster subclass carries it). Absent = non-caster.",
        +  "enum": [
        +    "full",
        +    "half",
        +    "third",
        +    "pact"
        +  ],
        +  "type": "string"
        +}
      • addedInput schema / properties / castingAbility
        Added value: +{
        +  "description": "The ability this rule's spellcasting keys off ('Intelligence is your spellcasting ability for your Wizard spells'). Author it on a class's Spellcasting ability rule; vault's creation and level-up wizards write it to the character-wide Spellcasting Ability (first-wins, never overwriting), and a multiclass whose ability differs stamps its granted spells per-entry. Distinct from a spell block's castingAbility, which overrides per grant. Absent = the rule says nothing about the character's casting ability.",
        +  "enum": [
        +    "strength",
        +    "dexterity",
        +    "constitution",
        +    "intelligence",
        +    "wisdom",
        +    "charisma"
        +  ],
        +  "type": "string"
        +}
      • addedInput schema / properties / categories
        Added value: +{
        +  "items": {
        +    "type": "string"
        +  },
        +  "type": "array"
        +}
      • addedInput schema / properties / creatureType
        Added value: +{
        +  "type": "string"
        +}
      • addedInput schema / properties / damage
        Added value: +{
        +  "additionalProperties": {},
        +  "properties": {
        +    "appliesTo": {
        +      "enum": [
        +        "melee",
        +        "ranged",
        +        "either"
        +      ],
        +      "type": "string"
        +    },
        +    "area": {
        +      "items": {
        +        "additionalProperties": {},
        +        "properties": {
        +          "shape": {
        +            "enum": [
        +              "cone",
        +              "line",
        +              "sphere",
        +              "cube",
        +              "cylinder",
        +              "emanation",
        +              "radius"
        +            ],
        +            "type": "string"
        +          },
        +          "size": {
        +            "minimum": 0,
        +            "type": "number"
        +          },
        +          "width": {
        +            "minimum": 0,
        +            "type": "number"
        +          }
        +        },
        +        "type": "object"
        +      },
        +      "type": "array"
        +    },
        +    "dice": {
        +      "type": "string"
        +    },
        +    "flat": {
        +      "type": "number"
        +    },
        +    "modifierAbility": {
        +      "enum": [
        +        "strength",
        +        "dexterity",
        +        "constitution",
        +        "intelligence",
        +        "wisdom",
        +        "charisma"
        +      ],
        +      "type": "string"
        +    },
        +    "modifierType": {
        +      "enum": [
        +        "flat",
        +        "proficiency",
        +        "ability"
        +      ],
        +      "type": "string"
        +    },
        +    "onSave": {
        +      "enum": [
        +        "half",
        +        "negates",
        +        "full"
        +      ],
        +      "type": "string"
        +    },
        +    "progression": {
        +      "items": {
        +        "additionalProperties": {},
        +        "properties": {
        +          "dice": {
        +            "type": "string"
        +          },
        +          "flat": {
        +            "type": "number"
        +          },
        +          "level": {
        +            "maximum": 20,
        +            "minimum": 1,
        +            "type": "integer"
        +          }
        +        },
        +        "type": "object"
        +      },
        +      "type": "array"
        +    },
        +    "save": {
        +      "additionalProperties": {},
        +      "properties": {
        +        "ability": {
        +          "enum": [
        +            "none",
        +            "spellcasting",
        +            "attackAttribute",
        +            "strength",
        +            "dexterity",
        +            "constitution",
        +            "intelligence",
        +            "wisdom",
        +            "charisma"
        +          ],
        +          "type": "string"
        +        },
        +        "dcBase": {
        +          "type": "number"
        +        },
        +        "includesProficiency": {
        +          "type": "boolean"
        +        },
        +        "saveType": {
        +          "enum": [
        +            "strength",
        +            "dexterity",
        +            "constitution",
        +            "intelligence",
        +            "wisdom",
        +            "charisma"
        +          ],
        +          "type": "string"
        +        }
        +      },
        +      "type": "object"
        +    },
        +    "scaling": {
        +      "enum": [
        +        "fixed",
        +        "byLevel",
        +        "spellSlot"
        +      ],
        +      "type": "string"
        +    },
        +    "scalingAttribute": {
        +      "type": "string"
        +    },
        +    "slotIncrement": {
        +      "additionalProperties": {},
        +      "properties": {
        +        "dice": {
        +          "type": "string"
        +        },
        +        "flat": {
        +          "type": "number"
        +        },
        +        "targets": {
        +          "maximum": 9007199254740991,
        +          "minimum": 1,
        +          "type": "integer"
        +        }
        +      },
        +      "type": "object"
        +    },
        +    "targets": {
        +      "additionalProperties": {},
        +      "properties": {
        +        "count": {
        +          "maximum": 9007199254740991,
        +          "minimum": 1,
        +          "type": "integer"
        +        }
        +      },
        +      "type": "object"
        +    },
        +    "trigger": {
        +      "enum": [
        +        "passive",
        +        "toggled",
        +        "reaction",
        +        "perRoll",
        +        "resource",
        +        "targetBound"
        +      ],
        +      "type": "string"
        +    },
        +    "types": {
        +      "items": {
        +        "type": "string"
        +      },
        +      "type": "array"
        +    }
        +  },
        +  "type": "object"
        +}
      • addedInput schema / properties / damageReduction
        Added value: +{
        +  "items": {
        +    "additionalProperties": {},
        +    "properties": {
        +      "amount": {
        +        "additionalProperties": {},
        +        "properties": {
        +          "dice": {
        +            "type": "string"
        +          },
        +          "flat": {
        +            "type": "number"
        +          },
        +          "includesProficiency": {
        +            "type": "boolean"
        +          },
        +          "modifierSource": {
        +            "enum": [
        +              "spellcasting",
        +              "attackAttribute",
        +              "strength",
        +              "dexterity",
        +              "constitution",
        +              "intelligence",
        +              "wisdom",
        +              "charisma"
        +            ],
        +            "type": "string"
        +          }
        +        },
        +        "type": "object"
        +      },
        +      "range": {
        +        "maximum": 9007199254740991,
        +        "minimum": 0,
        +        "type": "integer"
        +      },
        +      "requires": {
        +        "items": {
        +          "additionalProperties": {},
        +          "properties": {
        +            "armorCategories": {
        +              "description": "For 'equipped' + slot:armor: armor category list (Light / Medium / Heavy). OR semantics — match any.",
        +              "items": {
        +                "type": "string"
        +              },
        +              "type": "array"
        +            },
        +            "condition": {
        +              "description": "For 'condition' predicates: the character-state condition to gate on (5e24 named conditions and ongoing-action states).",
        +              "enum": [
        +                "blinded",
        +                "charmed",
        +                "dazed",
        +                "deafened",
        +                "exhaustion",
        +                "frightened",
        +                "grappled",
        +                "incapacitated",
        +                "invisible",
        +                "paralyzed",
        +                "petrified",
        +                "poisoned",
        +                "prone",
        +                "restrained",
        +                "stunned",
        +                "unconscious",
        +                "concentrating",
        +                "grappling",
        +                "dodging",
        +                "hiding",
        +                "raging"
        +              ],
        +              "type": "string"
        +            },
        +            "equipSlot": {
        +              "description": "Body slot the matched weapon must occupy. mainHand / offHand. Resolved via getRequiredSlots so two-handed grips occupy both.",
        +              "enum": [
        +                "mainHand",
        +                "offHand"
        +              ],
        +              "type": "string"
        +            },
        +            "negate": {
        +              "description": "true inverts the predicate — 'while NOT matching' instead of 'while matching'.",
        +              "type": "boolean"
        +            },
        +            "slot": {
        +              "description": "For 'equipped' predicates: the body category to match (armor / shield / weapon).",
        +              "enum": [
        +                "armor",
        +                "shield",
        +                "weapon"
        +              ],
        +              "type": "string"
        +            },
        +            "type": {
        +              "description": "Predicate type. 'equipped' = character-scoped (gates on what's equipped). 'attackingWeapon' = attack-scoped (gates on the current action's source weapon). 'condition' = gates on a character-state condition.",
        +              "enum": [
        +                "equipped",
        +                "attackingWeapon",
        +                "condition"
        +              ],
        +              "type": "string"
        +            },
        +            "weaponProperties": {
        +              "description": "For 'equipped' + slot:weapon OR 'attackingWeapon': weapon-property list. AND semantics — match all.",
        +              "items": {
        +                "type": "string"
        +              },
        +              "type": "array"
        +            }
        +          },
        +          "type": "object"
        +        },
        +        "type": "array"
        +      },
        +      "requiresLogic": {
        +        "enum": [
        +          "and",
        +          "or"
        +        ],
        +        "type": "string"
        +      },
        +      "target": {
        +        "enum": [
        +          "self",
        +          "ally",
        +          "any",
        +          "target",
        +          "enemy"
        +        ],
        +        "type": "string"
        +      },
        +      "trigger": {
        +        "enum": [
        +          "passive",
        +          "toggled",
        +          "reaction",
        +          "perRoll",
        +          "resource",
        +          "targetBound"
        +        ],
        +        "type": "string"
        +      },
        +      "types": {
        +        "items": {
        +          "type": "string"
        +        },
        +        "type": "array"
        +      }
        +    },
        +    "type": "object"
        +  },
        +  "type": "array"
        +}
      • addedInput schema / properties / defaultAbilityScores
        Added value: +{
        +  "additionalProperties": {},
        +  "properties": {
        +    "charisma": {
        +      "maximum": 30,
        +      "minimum": 1,
        +      "type": "integer"
        +    },
        +    "constitution": {
        +      "maximum": 30,
        +      "minimum": 1,
        +      "type": "integer"
        +    },
        +    "dexterity": {
        +      "maximum": 30,
        +      "minimum": 1,
        +      "type": "integer"
        +    },
        +    "intelligence": {
        +      "maximum": 30,
        +      "minimum": 1,
        +      "type": "integer"
        +    },
        +    "strength": {
        +      "maximum": 30,
        +      "minimum": 1,
        +      "type": "integer"
        +    },
        +    "wisdom": {
        +      "maximum": 30,
        +      "minimum": 1,
        +      "type": "integer"
        +    }
        +  },
        +  "type": "object"
        +}
      • addedInput schema / properties / description
        Added value: +{
        +  "description": "Full rule body. Markdown is supported.",
        +  "type": "string"
        +}
      • addedInput schema / properties / diceFloors
        Added value: +{
        +  "items": {
        +    "additionalProperties": {},
        +    "properties": {
        +      "appliesTo": {
        +        "enum": [
        +          "damage",
        +          "damage.melee",
        +          "damage.ranged",
        +          "damage.spell",
        +          "healing"
        +        ],
        +        "type": "string"
        +      },
        +      "floor": {
        +        "maximum": 9007199254740991,
        +        "minimum": 1,
        +        "type": "integer"
        +      },
        +      "requires": {
        +        "items": {
        +          "additionalProperties": {},
        +          "properties": {
        +            "armorCategories": {
        +              "description": "For 'equipped' + slot:armor: armor category list (Light / Medium / Heavy). OR semantics — match any.",
        +              "items": {
        +                "type": "string"
        +              },
        +              "type": "array"
        +            },
        +            "condition": {
        +              "description": "For 'condition' predicates: the character-state condition to gate on (5e24 named conditions and ongoing-action states).",
        +              "enum": [
        +                "blinded",
        +                "charmed",
        +                "dazed",
        +                "deafened",
        +                "exhaustion",
        +                "frightened",
        +                "grappled",
        +                "incapacitated",
        +                "invisible",
        +                "paralyzed",
        +                "petrified",
        +                "poisoned",
        +                "prone",
        +                "restrained",
        +                "stunned",
        +                "unconscious",
        +                "concentrating",
        +                "grappling",
        +                "dodging",
        +                "hiding",
        +                "raging"
        +              ],
        +              "type": "string"
        +            },
        +            "equipSlot": {
        +              "description": "Body slot the matched weapon must occupy. mainHand / offHand. Resolved via getRequiredSlots so two-handed grips occupy both.",
        +              "enum": [
        +                "mainHand",
        +                "offHand"
        +              ],
        +              "type": "string"
        +            },
        +            "negate": {
        +              "description": "true inverts the predicate — 'while NOT matching' instead of 'while matching'.",
        +              "type": "boolean"
        +            },
        +            "slot": {
        +              "description": "For 'equipped' predicates: the body category to match (armor / shield / weapon).",
        +              "enum": [
        +                "armor",
        +                "shield",
        +                "weapon"
        +              ],
        +              "type": "string"
        +            },
        +            "type": {
        +              "description": "Predicate type. 'equipped' = character-scoped (gates on what's equipped). 'attackingWeapon' = attack-scoped (gates on the current action's source weapon). 'condition' = gates on a character-state condition.",
        +              "enum": [
        +                "equipped",
        +                "attackingWeapon",
        +                "condition"
        +              ],
        +              "type": "string"
        +            },
        +            "weaponProperties": {
        +              "description": "For 'equipped' + slot:weapon OR 'attackingWeapon': weapon-property list. AND semantics — match all.",
        +              "items": {
        +                "type": "string"
        +              },
        +              "type": "array"
        +            }
        +          },
        +          "type": "object"
        +        },
        +        "type": "array"
        +      },
        +      "requiresLogic": {
        +        "enum": [
        +          "and",
        +          "or"
        +        ],
        +        "type": "string"
        +      },
        +      "threshold": {
        +        "maximum": 9007199254740991,
        +        "minimum": 1,
        +        "type": "integer"
        +      },
        +      "trigger": {
        +        "enum": [
        +          "passive",
        +          "toggled",
        +          "reaction",
        +          "perRoll",
        +          "resource",
        +          "targetBound"
        +        ],
        +        "type": "string"
        +      }
        +    },
        +    "type": "object"
        +  },
        +  "type": "array"
        +}
      • addedInput schema / properties / diceReplacements
        Added value: +{
        +  "items": {
        +    "additionalProperties": {},
        +    "properties": {
        +      "_target": {
        +        "description": "Mongo `_id` reference (24-character hex string).",
        +        "minLength": 1,
        +        "type": "string"
        +      },
        +      "dice": {
        +        "type": "string"
        +      },
        +      "progression": {
        +        "items": {
        +          "additionalProperties": {},
        +          "properties": {
        +            "dice": {
        +              "type": "string"
        +            },
        +            "level": {
        +              "maximum": 20,
        +              "minimum": 1,
        +              "type": "integer"
        +            }
        +          },
        +          "type": "object"
        +        },
        +        "type": "array"
        +      },
        +      "requires": {
        +        "items": {
        +          "additionalProperties": {},
        +          "properties": {
        +            "armorCategories": {
        +              "description": "For 'equipped' + slot:armor: armor category list (Light / Medium / Heavy). OR semantics — match any.",
        +              "items": {
        +                "type": "string"
        +              },
        +              "type": "array"
        +            },
        +            "condition": {
        +              "description": "For 'condition' predicates: the character-state condition to gate on (5e24 named conditions and ongoing-action states).",
        +              "enum": [
        +                "blinded",
        +                "charmed",
        +                "dazed",
        +                "deafened",
        +                "exhaustion",
        +                "frightened",
        +                "grappled",
        +                "incapacitated",
        +                "invisible",
        +                "paralyzed",
        +                "petrified",
        +                "poisoned",
        +                "prone",
        +                "restrained",
        +                "stunned",
        +                "unconscious",
        +                "concentrating",
        +                "grappling",
        +                "dodging",
        +                "hiding",
        +                "raging"
        +              ],
        +              "type": "string"
        +            },
        +            "equipSlot": {
        +              "description": "Body slot the matched weapon must occupy. mainHand / offHand. Resolved via getRequiredSlots so two-handed grips occupy both.",
        +              "enum": [
        +                "mainHand",
        +                "offHand"
        +              ],
        +              "type": "string"
        +            },
        +            "negate": {
        +              "description": "true inverts the predicate — 'while NOT matching' instead of 'while matching'.",
        +              "type": "boolean"
        +            },
        +            "slot": {
        +              "description": "For 'equipped' predicates: the body category to match (armor / shield / weapon).",
        +              "enum": [
        +                "armor",
        +                "shield",
        +                "weapon"
        +              ],
        +              "type": "string"
        +            },
        +            "type": {
        +              "description": "Predicate type. 'equipped' = character-scoped (gates on what's equipped). 'attackingWeapon' = attack-scoped (gates on the current action's source weapon). 'condition' = gates on a character-state condition.",
        +              "enum": [
        +                "equipped",
        +                "attackingWeapon",
        +                "condition"
        +              ],
        +              "type": "string"
        +            },
        +            "weaponProperties": {
        +              "description": "For 'equipped' + slot:weapon OR 'attackingWeapon': weapon-property list. AND semantics — match all.",
        +              "items": {
        +                "type": "string"
        +              },
        +              "type": "array"
        +            }
        +          },
        +          "type": "object"
        +        },
        +        "type": "array"
        +      },
        +      "requiresLogic": {
        +        "enum": [
        +          "and",
        +          "or"
        +        ],
        +        "type": "string"
        +      }
        +    },
        +    "type": "object"
        +  },
        +  "type": "array"
        +}
      • addedInput schema / properties / duration
        Added value: +{
        +  "additionalProperties": {},
        +  "properties": {
        +    "concentration": {
        +      "type": "boolean"
        +    },
        +    "count": {
        +      "maximum": 9007199254740991,
        +      "minimum": 0,
        +      "type": "integer"
        +    },
        +    "unit": {
        +      "enum": [
        +        "round",
        +        "minute",
        +        "hour",
        +        "day",
        +        "untilShortRest",
        +        "untilLongRest",
        +        "special"
        +      ],
        +      "type": "string"
        +    }
        +  },
        +  "type": "object"
        +}
      • addedInput schema / properties / effect
        Added value: +{
        +  "additionalProperties": {},
        +  "properties": {
        +    "audience": {
        +      "enum": [
        +        "self",
        +        "ally",
        +        "any",
        +        "target",
        +        "enemy"
        +      ],
        +      "type": "string"
        +    },
        +    "conditions": {
        +      "items": {
        +        "additionalProperties": {},
        +        "properties": {
        +          "applyWhen": {
        +            "enum": [
        +              "always",
        +              "onFail",
        +              "onSuccess"
        +            ],
        +            "type": "string"
        +          },
        +          "durationCount": {
        +            "maximum": 9007199254740991,
        +            "minimum": 0,
        +            "type": "integer"
        +          },
        +          "durationUnit": {
        +            "enum": [
        +              "round",
        +              "minute",
        +              "hour",
        +              "day",
        +              "untilShortRest",
        +              "untilLongRest",
        +              "special"
        +            ],
        +            "type": "string"
        +          },
        +          "name": {
        +            "type": "string"
        +          },
        +          "target": {
        +            "enum": [
        +              "self",
        +              "target"
        +            ],
        +            "type": "string"
        +          }
        +        },
        +        "type": "object"
        +      },
        +      "type": "array"
        +    },
        +    "save": {
        +      "additionalProperties": {},
        +      "properties": {
        +        "ability": {
        +          "enum": [
        +            "none",
        +            "spellcasting",
        +            "attackAttribute",
        +            "strength",
        +            "dexterity",
        +            "constitution",
        +            "intelligence",
        +            "wisdom",
        +            "charisma"
        +          ],
        +          "type": "string"
        +        },
        +        "dcBase": {
        +          "type": "number"
        +        },
        +        "includesProficiency": {
        +          "type": "boolean"
        +        },
        +        "saveType": {
        +          "enum": [
        +            "strength",
        +            "dexterity",
        +            "constitution",
        +            "intelligence",
        +            "wisdom",
        +            "charisma"
        +          ],
        +          "type": "string"
        +        }
        +      },
        +      "type": "object"
        +    },
        +    "triggerEvent": {
        +      "enum": [
        +        "onHit",
        +        "onMiss",
        +        "onDamage",
        +        "startOfYourTurn",
        +        "endOfYourTurn",
        +        "startOfTargetTurn",
        +        "endOfTargetTurn"
        +      ],
        +      "type": "string"
        +    }
        +  },
        +  "type": "object"
        +}
      • addedInput schema / properties / feat
        Added value: +{
        +  "description": "Mongo `_id` reference (24-character hex string).",
        +  "minLength": 1,
        +  "type": "string"
        +}
      • addedInput schema / properties / featOpen
        Added value: +{
        +  "type": "boolean"
        +}
      • addedInput schema / properties / forcedMovement
        Added value: +{
        +  "items": {
        +    "additionalProperties": {},
        +    "properties": {
        +      "audience": {
        +        "enum": [
        +          "self",
        +          "ally",
        +          "any",
        +          "target",
        +          "enemy"
        +        ],
        +        "type": "string"
        +      },
        +      "direction": {
        +        "enum": [
        +          "awayFromSelf",
        +          "towardSelf",
        +          "anywhere"
        +        ],
        +        "type": "string"
        +      },
        +      "distance": {
        +        "maximum": 9007199254740991,
        +        "minimum": 0,
        +        "type": "integer"
        +      },
        +      "maxTargetSize": {
        +        "enum": [
        +          "tiny",
        +          "small",
        +          "medium",
        +          "large",
        +          "huge",
        +          "gargantuan"
        +        ],
        +        "type": "string"
        +      },
        +      "requires": {
        +        "items": {
        +          "additionalProperties": {},
        +          "properties": {
        +            "armorCategories": {
        +              "description": "For 'equipped' + slot:armor: armor category list (Light / Medium / Heavy). OR semantics — match any.",
        +              "items": {
        +                "type": "string"
        +              },
        +              "type": "array"
        +            },
        +            "condition": {
        +              "description": "For 'condition' predicates: the character-state condition to gate on (5e24 named conditions and ongoing-action states).",
        +              "enum": [
        +                "blinded",
        +                "charmed",
        +                "dazed",
        +                "deafened",
        +                "exhaustion",
        +                "frightened",
        +                "grappled",
        +                "incapacitated",
        +                "invisible",
        +                "paralyzed",
        +                "petrified",
        +                "poisoned",
        +                "prone",
        +                "restrained",
        +                "stunned",
        +                "unconscious",
        +                "concentrating",
        +                "grappling",
        +                "dodging",
        +                "hiding",
        +                "raging"
        +              ],
        +              "type": "string"
        +            },
        +            "equipSlot": {
        +              "description": "Body slot the matched weapon must occupy. mainHand / offHand. Resolved via getRequiredSlots so two-handed grips occupy both.",
        +              "enum": [
        +                "mainHand",
        +                "offHand"
        +              ],
        +              "type": "string"
        +            },
        +            "negate": {
        +              "description": "true inverts the predicate — 'while NOT matching' instead of 'while matching'.",
        +              "type": "boolean"
        +            },
        +            "slot": {
        +              "description": "For 'equipped' predicates: the body category to match (armor / shield / weapon).",
        +              "enum": [
        +                "armor",
        +                "shield",
        +                "weapon"
        +              ],
        +              "type": "string"
        +            },
        +            "type": {
        +              "description": "Predicate type. 'equipped' = character-scoped (gates on what's equipped). 'attackingWeapon' = attack-scoped (gates on the current action's source weapon). 'condition' = gates on a character-state condition.",
        +              "enum": [
        +                "equipped",
        +                "attackingWeapon",
        +                "condition"
        +              ],
        +              "type": "string"
        +            },
        +            "weaponProperties": {
        +              "description": "For 'equipped' + slot:weapon OR 'attackingWeapon': weapon-property list. AND semantics — match all.",
        +              "items": {
        +                "type": "string"
        +              },
        +              "type": "array"
        +            }
        +          },
        +          "type": "object"
        +        },
        +        "type": "array"
        +      },
        +      "requiresLogic": {
        +        "enum": [
        +          "and",
        +          "or"
        +        ],
        +        "type": "string"
        +      },
        +      "triggerEvent": {
        +        "enum": [
        +          "onHit",
        +          "onMiss",
        +          "onDamage",
        +          "startOfYourTurn",
        +          "endOfYourTurn",
        +          "startOfTargetTurn",
        +          "endOfTargetTurn"
        +        ],
        +        "type": "string"
        +      }
        +    },
        +    "type": "object"
        +  },
        +  "type": "array"
        +}
      • addedInput schema / properties / healing
        Added value: +{
        +  "additionalProperties": {},
        +  "properties": {
        +    "dice": {
        +      "type": "string"
        +    },
        +    "flat": {
        +      "type": "number"
        +    },
        +    "modifierSource": {
        +      "enum": [
        +        "level",
        +        "spellcasting",
        +        "strength",
        +        "dexterity",
        +        "constitution",
        +        "intelligence",
        +        "wisdom",
        +        "charisma"
        +      ],
        +      "type": "string"
        +    },
        +    "progression": {
        +      "items": {
        +        "additionalProperties": {},
        +        "properties": {
        +          "dice": {
        +            "type": "string"
        +          },
        +          "flat": {
        +            "type": "number"
        +          },
        +          "level": {
        +            "maximum": 20,
        +            "minimum": 1,
        +            "type": "integer"
        +          }
        +        },
        +        "type": "object"
        +      },
        +      "type": "array"
        +    },
        +    "scaling": {
        +      "enum": [
        +        "fixed",
        +        "byLevel",
        +        "proficiency",
        +        "spellSlot"
        +      ],
        +      "type": "string"
        +    },
        +    "slotIncrement": {
        +      "additionalProperties": {},
        +      "properties": {
        +        "dice": {
        +          "type": "string"
        +        },
        +        "flat": {
        +          "type": "number"
        +        }
        +      },
        +      "type": "object"
        +    },
        +    "target": {
        +      "enum": [
        +        "self",
        +        "ally",
        +        "any",
        +        "multiple"
        +      ],
        +      "type": "string"
        +    },
        +    "targets": {
        +      "additionalProperties": {},
        +      "properties": {
        +        "count": {
        +          "maximum": 9007199254740991,
        +          "minimum": 1,
        +          "type": "integer"
        +        }
        +      },
        +      "type": "object"
        +    }
        +  },
        +  "type": "object"
        +}
      • addedInput schema / properties / hitDie
        Added value: +{
        +  "type": "string"
        +}
      • addedInput schema / properties / image
        Added value: +{
        +  "additionalProperties": {},
        +  "properties": {
        +    "url": {
        +      "description": "Image URL hosted on Embers Images (or any addressable HTTPS URL).",
        +      "type": "string"
        +    }
        +  },
        +  "type": "object"
        +}
      • addedInput schema / properties / keywords
        Added value: +{
        +  "items": {
        +    "type": "string"
        +  },
        +  "type": "array"
        +}
      • addedInput schema / properties / languages
        Added value: +{
        +  "additionalProperties": {},
        +  "properties": {
        +    "choose": {
        +      "additionalProperties": {},
        +      "properties": {
        +        "count": {
        +          "maximum": 9007199254740991,
        +          "minimum": 0,
        +          "type": "integer"
        +        },
        +        "options": {
        +          "items": {
        +            "type": "string"
        +          },
        +          "type": "array"
        +        }
        +      },
        +      "type": "object"
        +    },
        +    "fixed": {
        +      "items": {
        +        "type": "string"
        +      },
        +      "type": "array"
        +    }
        +  },
        +  "type": "object"
        +}
      • addedInput schema / properties / levelProgression
        Added value: +{
        +  "items": {
        +    "additionalProperties": {},
        +    "properties": {
        +      "name": {
        +        "type": "string"
        +      },
        +      "values": {
        +        "items": {
        +          "type": "string"
        +        },
        +        "type": "array"
        +      }
        +    },
        +    "type": "object"
        +  },
        +  "type": "array"
        +}
      • addedInput schema / properties / mechanicsKey
        Added value: +{
        +  "type": "string"
        +}
      • addedInput schema / properties / multiclassing
        Added value: +{
        +  "additionalProperties": {},
        +  "description": "What multiclassing INTO this class grants (weapon/armor lists apply fixed; skillChoices/toolChoices render pickers). Absent = no multiclass proficiencies.",
        +  "properties": {
        +    "armorTraining": {
        +      "items": {
        +        "type": "string"
        +      },
        +      "type": "array"
        +    },
        +    "skillChoices": {
        +      "additionalProperties": {},
        +      "properties": {
        +        "count": {
        +          "maximum": 9007199254740991,
        +          "minimum": 0,
        +          "type": "integer"
        +        },
        +        "options": {
        +          "items": {
        +            "type": "string"
        +          },
        +          "type": "array"
        +        }
        +      },
        +      "type": "object"
        +    },
        +    "toolChoices": {
        +      "additionalProperties": {},
        +      "properties": {
        +        "count": {
        +          "maximum": 9007199254740991,
        +          "minimum": 0,
        +          "type": "integer"
        +        },
        +        "options": {
        +          "items": {
        +            "type": "string"
        +          },
        +          "type": "array"
        +        }
        +      },
        +      "type": "object"
        +    },
        +    "toolProficiencies": {
        +      "items": {
        +        "type": "string"
        +      },
        +      "type": "array"
        +    },
        +    "weaponProficiencies": {
        +      "items": {
        +        "type": "string"
        +      },
        +      "type": "array"
        +    }
        +  },
        +  "type": "object"
        +}
      • addedInput schema / properties / name
        Added value: +{
        +  "description": "Display name. Required.",
        +  "minLength": 1,
        +  "type": "string"
        +}
      • addedInput schema / properties / ogl
        Added value: +{
        +  "type": "boolean"
        +}
      • addedInput schema / properties / parameters
        Added value: +{
        +  "items": {
        +    "additionalProperties": {},
        +    "properties": {
        +      "label": {
        +        "type": "string"
        +      },
        +      "max": {
        +        "type": "number"
        +      },
        +      "min": {
        +        "type": "number"
        +      },
        +      "name": {
        +        "type": "string"
        +      },
        +      "type": {
        +        "enum": [
        +          "number",
        +          "string",
        +          "enum"
        +        ],
        +        "type": "string"
        +      },
        +      "unit": {
        +        "type": "string"
        +      }
        +    },
        +    "type": "object"
        +  },
        +  "type": "array"
        +}
      • addedInput schema / properties / preparedSpells
        Added value: +{
        +  "additionalProperties": {},
        +  "properties": {
        +    "count": {
        +      "maximum": 9007199254740991,
        +      "minimum": 0,
        +      "type": "integer"
        +    },
        +    "progression": {
        +      "items": {
        +        "additionalProperties": {},
        +        "properties": {
        +          "count": {
        +            "maximum": 9007199254740991,
        +            "minimum": 0,
        +            "type": "integer"
        +          },
        +          "level": {
        +            "maximum": 20,
        +            "minimum": 1,
        +            "type": "integer"
        +          }
        +        },
        +        "type": "object"
        +      },
        +      "type": "array"
        +    }
        +  },
        +  "type": "object"
        +}
      • addedInput schema / properties / prerequisites
        Added value: +{
        +  "items": {
        +    "additionalProperties": {},
        +    "properties": {
        +      "abilities": {
        +        "description": "For abilityScore: ANY listed ability meeting `min` satisfies ('Str or Dex 13+').",
        +        "items": {
        +          "enum": [
        +            "strength",
        +            "dexterity",
        +            "constitution",
        +            "intelligence",
        +            "wisdom",
        +            "charisma"
        +          ],
        +          "type": "string"
        +        },
        +        "type": "array"
        +      },
        +      "category": {
        +        "description": "For rule (filter): matches any held rule in this category.",
        +        "type": "string"
        +      },
        +      "class": {
        +        "description": "For a `level` predicate: a Class rule id that scopes `min` to 'Nth level in that class'. Absent = total character level.",
        +        "minLength": 1,
        +        "type": "string"
        +      },
        +      "min": {
        +        "description": "Numeric minimum — character level (level), class level (class), or ability score (abilityScore).",
        +        "maximum": 9007199254740991,
        +        "minimum": 0,
        +        "type": "integer"
        +      },
        +      "negate": {
        +        "description": "true inverts the predicate — 'must NOT meet this'.",
        +        "type": "boolean"
        +      },
        +      "proficiency": {
        +        "description": "For proficiency: the proficiency name (e.g. 'Martial', 'Stealth').",
        +        "type": "string"
        +      },
        +      "proficiencyType": {
        +        "description": "For proficiency: the family.",
        +        "enum": [
        +          "skill",
        +          "tool",
        +          "weapon",
        +          "armor",
        +          "save",
        +          "language"
        +        ],
        +        "type": "string"
        +      },
        +      "rule": {
        +        "description": "For rule: a specific held Rule id.",
        +        "minLength": 1,
        +        "type": "string"
        +      },
        +      "ruleType": {
        +        "description": "For rule (filter): matches any held rule of this type.",
        +        "type": "string"
        +      },
        +      "spell": {
        +        "description": "For spell: a specific known Spell id.",
        +        "minLength": 1,
        +        "type": "string"
        +      },
        +      "spellList": {
        +        "description": "For spell (filter): knows any spell from this class list.",
        +        "type": "string"
        +      },
        +      "type": {
        +        "description": "Predicate kind: level / abilityScore / rule / spell / proficiency / spellcasting. (A class is required via a `rule` predicate pointing at the class rule.)",
        +        "enum": [
        +          "level",
        +          "abilityScore",
        +          "rule",
        +          "spell",
        +          "proficiency",
        +          "spellcasting"
        +        ],
        +        "type": "string"
        +      }
        +    },
        +    "type": "object"
        +  },
        +  "type": "array"
        +}
      • addedInput schema / properties / prerequisitesLogic
        Added value: +{
        +  "enum": [
        +    "and",
        +    "or"
        +  ],
        +  "type": "string"
        +}
      • addedInput schema / properties / proficiencyChoices
        Added value: +{
        +  "items": {
        +    "additionalProperties": {},
        +    "properties": {
        +      "allowedItems": {
        +        "items": {
        +          "type": "string"
        +        },
        +        "type": "array"
        +      },
        +      "level": {
        +        "enum": [
        +          "proficient",
        +          "expertise"
        +        ],
        +        "type": "string"
        +      },
        +      "mode": {
        +        "enum": [
        +          "specific",
        +          "all"
        +        ],
        +        "type": "string"
        +      },
        +      "progression": {
        +        "items": {
        +          "additionalProperties": {},
        +          "properties": {
        +            "count": {
        +              "maximum": 9007199254740991,
        +              "minimum": 0,
        +              "type": "integer"
        +            },
        +            "level": {
        +              "maximum": 20,
        +              "minimum": 1,
        +              "type": "integer"
        +            }
        +          },
        +          "type": "object"
        +        },
        +        "type": "array"
        +      },
        +      "types": {
        +        "items": {
        +          "enum": [
        +            "skill",
        +            "tool",
        +            "save",
        +            "weapon",
        +            "armor",
        +            "language"
        +          ],
        +          "type": "string"
        +        },
        +        "type": "array"
        +      }
        +    },
        +    "type": "object"
        +  },
        +  "type": "array"
        +}
      • addedInput schema / properties / publisher
        Added value: +{
        +  "type": "string"
        +}
      • addedInput schema / properties / range
        Added value: +{
        +  "additionalProperties": {},
        +  "description": "How far the ability reaches when invoked — self, touch, or ranged with a distance ('feet' default, 'miles' for long reaches). Absent = runtime defaults (self-heals on the user, targeted abilities at touch).",
        +  "properties": {
        +    "distance": {
        +      "minimum": 0,
        +      "type": "number"
        +    },
        +    "kind": {
        +      "enum": [
        +        "self",
        +        "touch",
        +        "ranged",
        +        "sight",
        +        "unlimited",
        +        "special"
        +      ],
        +      "type": "string"
        +    },
        +    "unit": {
        +      "enum": [
        +        "feet",
        +        "miles"
        +      ],
        +      "type": "string"
        +    }
        +  },
        +  "type": "object"
        +}
      • addedInput schema / properties / recurringDamage
        Added value: +{
        +  "items": {
        +    "additionalProperties": {},
        +    "properties": {
        +      "amount": {
        +        "additionalProperties": {},
        +        "properties": {
        +          "dice": {
        +            "type": "string"
        +          },
        +          "flat": {
        +            "type": "number"
        +          },
        +          "includesProficiency": {
        +            "type": "boolean"
        +          },
        +          "modifierSource": {
        +            "enum": [
        +              "spellcasting",
        +              "attackAttribute",
        +              "strength",
        +              "dexterity",
        +              "constitution",
        +              "intelligence",
        +              "wisdom",
        +              "charisma"
        +            ],
        +            "type": "string"
        +          }
        +        },
        +        "type": "object"
        +      },
        +      "audience": {
        +        "enum": [
        +          "self",
        +          "ally",
        +          "any",
        +          "target",
        +          "enemy"
        +        ],
        +        "type": "string"
        +      },
        +      "durationCount": {
        +        "maximum": 9007199254740991,
        +        "minimum": 0,
        +        "type": "integer"
        +      },
        +      "durationUnit": {
        +        "enum": [
        +          "instantaneous",
        +          "untilStartOfNextTurn",
        +          "untilEndOfNextTurn",
        +          "round",
        +          "minute",
        +          "hour",
        +          "untilShortRest",
        +          "untilLongRest"
        +        ],
        +        "type": "string"
        +      },
        +      "ignoreResistances": {
        +        "type": "boolean"
        +      },
        +      "inheritDamageType": {
        +        "type": "boolean"
        +      },
        +      "range": {
        +        "maximum": 9007199254740991,
        +        "minimum": 0,
        +        "type": "integer"
        +      },
        +      "requires": {
        +        "items": {
        +          "additionalProperties": {},
        +          "properties": {
        +            "armorCategories": {
        +              "description": "For 'equipped' + slot:armor: armor category list (Light / Medium / Heavy). OR semantics — match any.",
        +              "items": {
        +                "type": "string"
        +              },
        +              "type": "array"
        +            },
        +            "condition": {
        +              "description": "For 'condition' predicates: the character-state condition to gate on (5e24 named conditions and ongoing-action states).",
        +              "enum": [
        +                "blinded",
        +                "charmed",
        +                "dazed",
        +                "deafened",
        +                "exhaustion",
        +                "frightened",
        +                "grappled",
        +                "incapacitated",
        +                "invisible",
        +                "paralyzed",
        +                "petrified",
        +                "poisoned",
        +                "prone",
        +                "restrained",
        +                "stunned",
        +                "unconscious",
        +                "concentrating",
        +                "grappling",
        +                "dodging",
        +                "hiding",
        +                "raging"
        +              ],
        +              "type": "string"
        +            },
        +            "equipSlot": {
        +              "description": "Body slot the matched weapon must occupy. mainHand / offHand. Resolved via getRequiredSlots so two-handed grips occupy both.",
        +              "enum": [
        +                "mainHand",
        +                "offHand"
        +              ],
        +              "type": "string"
        +            },
        +            "negate": {
        +              "description": "true inverts the predicate — 'while NOT matching' instead of 'while matching'.",
        +              "type": "boolean"
        +            },
        +            "slot": {
        +              "description": "For 'equipped' predicates: the body category to match (armor / shield / weapon).",
        +              "enum": [
        +                "armor",
        +                "shield",
        +                "weapon"
        +              ],
        +              "type": "string"
        +            },
        +            "type": {
        +              "description": "Predicate type. 'equipped' = character-scoped (gates on what's equipped). 'attackingWeapon' = attack-scoped (gates on the current action's source weapon). 'condition' = gates on a character-state condition.",
        +              "enum": [
        +                "equipped",
        +                "attackingWeapon",
        +                "condition"
        +              ],
        +              "type": "string"
        +            },
        +            "weaponProperties": {
        +              "description": "For 'equipped' + slot:weapon OR 'attackingWeapon': weapon-property list. AND semantics — match all.",
        +              "items": {
        +                "type": "string"
        +              },
        +              "type": "array"
        +            }
        +          },
        +          "type": "object"
        +        },
        +        "type": "array"
        +      },
        +      "requiresLogic": {
        +        "enum": [
        +          "and",
        +          "or"
        +        ],
        +        "type": "string"
        +      },
        +      "triggerEvent": {
        +        "enum": [
        +          "startOfYourTurn",
        +          "endOfYourTurn",
        +          "startOfTargetTurn",
        +          "endOfTargetTurn",
        +          "whenTargetEntersArea",
        +          "onHit",
        +          "onMiss",
        +          "onDamage"
        +        ],
        +        "type": "string"
        +      },
        +      "types": {
        +        "items": {
        +          "type": "string"
        +        },
        +        "type": "array"
        +      }
        +    },
        +    "type": "object"
        +  },
        +  "type": "array"
        +}
      • addedInput schema / properties / repeatable
        Added value: +{
        +  "description": "A rule that may be taken/granted more than once, each time as a distinct instance with its own sub-choices — a repeatable Feat (Skilled, Resilient), or a class's Ability Score Improvement ability, which its class grants at several levels.",
        +  "type": "boolean"
        +}
      • addedInput schema / properties / resistances
        Added value: +{
        +  "items": {
        +    "additionalProperties": {},
        +    "properties": {
        +      "mode": {
        +        "enum": [
        +          "resistance",
        +          "immunity",
        +          "vulnerability"
        +        ],
        +        "type": "string"
        +      },
        +      "range": {
        +        "description": "Aura radius in feet for ally/any-targeted resistances (Warding Aura's 10 ft.). Absent = self-only.",
        +        "maximum": 9007199254740991,
        +        "minimum": 0,
        +        "type": "integer"
        +      },
        +      "target": {
        +        "description": "Who the resistance protects — mirrors damageReduction's target/range pair. Absent = self.",
        +        "enum": [
        +          "self",
        +          "ally",
        +          "any",
        +          "target",
        +          "enemy"
        +        ],
        +        "type": "string"
        +      },
        +      "trigger": {
        +        "enum": [
        +          "passive",
        +          "toggled",
        +          "reaction",
        +          "perRoll",
        +          "resource",
        +          "targetBound"
        +        ],
        +        "type": "string"
        +      },
        +      "types": {
        +        "items": {
        +          "type": "string"
        +        },
        +        "type": "array"
        +      }
        +    },
        +    "type": "object"
        +  },
        +  "type": "array"
        +}
      • addedInput schema / properties / rollMods
        Added value: +{
        +  "items": {
        +    "additionalProperties": {},
        +    "properties": {
        +      "audience": {
        +        "enum": [
        +          "self",
        +          "ally",
        +          "any",
        +          "target",
        +          "enemy"
        +        ],
        +        "type": "string"
        +      },
        +      "consumeOnUse": {
        +        "type": "boolean"
        +      },
        +      "durationCount": {
        +        "maximum": 9007199254740991,
        +        "minimum": 0,
        +        "type": "integer"
        +      },
        +      "durationUnit": {
        +        "enum": [
        +          "instantaneous",
        +          "untilStartOfNextTurn",
        +          "untilEndOfNextTurn",
        +          "round",
        +          "minute",
        +          "hour",
        +          "untilShortRest",
        +          "untilLongRest"
        +        ],
        +        "type": "string"
        +      },
        +      "mode": {
        +        "enum": [
        +          "advantage",
        +          "disadvantage"
        +        ],
        +        "type": "string"
        +      },
        +      "range": {
        +        "maximum": 9007199254740991,
        +        "minimum": 0,
        +        "type": "integer"
        +      },
        +      "requires": {
        +        "items": {
        +          "additionalProperties": {},
        +          "properties": {
        +            "armorCategories": {
        +              "description": "For 'equipped' + slot:armor: armor category list (Light / Medium / Heavy). OR semantics — match any.",
        +              "items": {
        +                "type": "string"
        +              },
        +              "type": "array"
        +            },
        +            "condition": {
        +              "description": "For 'condition' predicates: the character-state condition to gate on (5e24 named conditions and ongoing-action states).",
        +              "enum": [
        +                "blinded",
        +                "charmed",
        +                "dazed",
        +                "deafened",
        +                "exhaustion",
        +                "frightened",
        +                "grappled",
        +                "incapacitated",
        +                "invisible",
        +                "paralyzed",
        +                "petrified",
        +                "poisoned",
        +                "prone",
        +                "restrained",
        +                "stunned",
        +                "unconscious",
        +                "concentrating",
        +                "grappling",
        +                "dodging",
        +                "hiding",
        +                "raging"
        +              ],
        +              "type": "string"
        +            },
        +            "equipSlot": {
        +              "description": "Body slot the matched weapon must occupy. mainHand / offHand. Resolved via getRequiredSlots so two-handed grips occupy both.",
        +              "enum": [
        +                "mainHand",
        +                "offHand"
        +              ],
        +              "type": "string"
        +            },
        +            "negate": {
        +              "description": "true inverts the predicate — 'while NOT matching' instead of 'while matching'.",
        +              "type": "boolean"
        +            },
        +            "slot": {
        +              "description": "For 'equipped' predicates: the body category to match (armor / shield / weapon).",
        +              "enum": [
        +                "armor",
        +                "shield",
        +                "weapon"
        +              ],
        +              "type": "string"
        +            },
        +            "type": {
        +              "description": "Predicate type. 'equipped' = character-scoped (gates on what's equipped). 'attackingWeapon' = attack-scoped (gates on the current action's source weapon). 'condition' = gates on a character-state condition.",
        +              "enum": [
        +                "equipped",
        +                "attackingWeapon",
        +                "condition"
        +              ],
        +              "type": "string"
        +            },
        +            "weaponProperties": {
        +              "description": "For 'equipped' + slot:weapon OR 'attackingWeapon': weapon-property list. AND semantics — match all.",
        +              "items": {
        +                "type": "string"
        +              },
        +              "type": "array"
        +            }
        +          },
        +          "type": "object"
        +        },
        +        "type": "array"
        +      },
        +      "requiresLogic": {
        +        "enum": [
        +          "and",
        +          "or"
        +        ],
        +        "type": "string"
        +      },
        +      "rollScope": {
        +        "enum": [
        +          "attack",
        +          "save",
        +          "abilityCheck",
        +          "skillCheck"
        +        ],
        +        "type": "string"
        +      },
        +      "trigger": {
        +        "enum": [
        +          "passive",
        +          "toggled",
        +          "reaction",
        +          "perRoll",
        +          "resource",
        +          "targetBound"
        +        ],
        +        "type": "string"
        +      },
        +      "triggerEvent": {
        +        "enum": [
        +          "onHit",
        +          "onMiss",
        +          "onDamage",
        +          "startOfYourTurn",
        +          "endOfYourTurn",
        +          "startOfTargetTurn",
        +          "endOfTargetTurn"
        +        ],
        +        "type": "string"
        +      }
        +    },
        +    "type": "object"
        +  },
        +  "type": "array"
        +}
      • addedInput schema / properties / ruleChoice
        Added value: +{
        +  "additionalProperties": {},
        +  "properties": {
        +    "allowedCategories": {
        +      "items": {
        +        "type": "string"
        +      },
        +      "type": "array"
        +    },
        +    "allowedRuleParameters": {
        +      "additionalProperties": {
        +        "additionalProperties": {},
        +        "properties": {
        +          "damageType": {
        +            "type": "string"
        +          },
        +          "number": {
        +            "maximum": 9007199254740991,
        +            "minimum": 0,
        +            "type": "integer"
        +          },
        +          "range": {
        +            "maximum": 9007199254740991,
        +            "minimum": 0,
        +            "type": "integer"
        +          },
        +          "speed": {
        +            "maximum": 9007199254740991,
        +            "minimum": 0,
        +            "type": "integer"
        +          }
        +        },
        +        "type": "object"
        +      },
        +      "propertyNames": {
        +        "type": "string"
        +      },
        +      "type": "object"
        +    },
        +    "allowedRules": {
        +      "items": {
        +        "description": "Mongo `_id` reference (24-character hex string).",
        +        "minLength": 1,
        +        "type": "string"
        +      },
        +      "type": "array"
        +    },
        +    "allowedTypes": {
        +      "items": {
        +        "type": "string"
        +      },
        +      "type": "array"
        +    },
        +    "count": {
        +      "maximum": 9007199254740991,
        +      "minimum": 0,
        +      "type": "integer"
        +    },
        +    "label": {
        +      "type": "string"
        +    },
        +    "mode": {
        +      "enum": [
        +        "filter",
        +        "specific"
        +      ],
        +      "type": "string"
        +    },
        +    "progression": {
        +      "items": {
        +        "additionalProperties": {},
        +        "properties": {
        +          "count": {
        +            "maximum": 9007199254740991,
        +            "minimum": 0,
        +            "type": "integer"
        +          },
        +          "level": {
        +            "maximum": 20,
        +            "minimum": 1,
        +            "type": "integer"
        +          }
        +        },
        +        "type": "object"
        +      },
        +      "type": "array"
        +    },
        +    "scaling": {
        +      "enum": [
        +        "fixed",
        +        "byLevel"
        +      ],
        +      "type": "string"
        +    }
        +  },
        +  "type": "object"
        +}
      • addedInput schema / properties / ruleset
        Added value: +{
        +  "description": "Ruleset code (e.g. '5th Edition', '5e24', 'PFRPG', 'Savage Worlds', 'Universal').",
        +  "type": "string"
        +}
      • addedInput schema / properties / savingThrows
        Added value: +{
        +  "items": {
        +    "type": "string"
        +  },
        +  "type": "array"
        +}
      • addedInput schema / properties / size
        Added value: +{
        +  "items": {
        +    "type": "string"
        +  },
        +  "type": "array"
        +}
      • addedInput schema / properties / skillChoices
        Added value: +{
        +  "additionalProperties": {},
        +  "properties": {
        +    "count": {
        +      "maximum": 9007199254740991,
        +      "minimum": 0,
        +      "type": "integer"
        +    },
        +    "options": {
        +      "items": {
        +        "type": "string"
        +      },
        +      "type": "array"
        +    }
        +  },
        +  "type": "object"
        +}
      • addedInput schema / properties / skillProficiencies
        Added value: +{
        +  "items": {
        +    "type": "string"
        +  },
        +  "type": "array"
        +}
      • addedInput schema / properties / source
        Added value: +{
        +  "type": "string"
        +}
      • addedInput schema / properties / speed
        Added value: +{
        +  "maximum": 9007199254740991,
        +  "minimum": 0,
        +  "type": "integer"
        +}
      • addedInput schema / properties / spellAbilities
        Added value: +{
        +  "items": {
        +    "additionalProperties": {},
        +    "properties": {
        +      "_spell": {
        +        "description": "Mongo `_id` reference (24-character hex string).",
        +        "minLength": 1,
        +        "type": "string"
        +      },
        +      "level": {
        +        "maximum": 20,
        +        "minimum": 1,
        +        "type": "integer"
        +      }
        +    },
        +    "type": "object"
        +  },
        +  "type": "array"
        +}
      • addedInput schema / properties / spellChoices
        Added value: +{
        +  "items": {
        +    "additionalProperties": {},
        +    "properties": {
        +      "allowedCategories": {
        +        "items": {
        +          "type": "string"
        +        },
        +        "type": "array"
        +      },
        +      "allowedSchools": {
        +        "items": {
        +          "type": "string"
        +        },
        +        "type": "array"
        +      },
        +      "allowedSpells": {
        +        "items": {
        +          "description": "Mongo `_id` reference (24-character hex string).",
        +          "minLength": 1,
        +          "type": "string"
        +        },
        +        "type": "array"
        +      },
        +      "castingAbility": {
        +        "enum": [
        +          "strength",
        +          "dexterity",
        +          "constitution",
        +          "intelligence",
        +          "wisdom",
        +          "charisma"
        +        ],
        +        "type": "string"
        +      },
        +      "castingAbilityOptions": {
        +        "items": {
        +          "enum": [
        +            "strength",
        +            "dexterity",
        +            "constitution",
        +            "intelligence",
        +            "wisdom",
        +            "charisma"
        +          ],
        +          "type": "string"
        +        },
        +        "type": "array"
        +      },
        +      "freeCast": {
        +        "additionalProperties": {},
        +        "properties": {
        +          "atWill": {
        +            "type": "boolean"
        +          },
        +          "count": {
        +            "maximum": 9007199254740991,
        +            "minimum": 0,
        +            "type": "integer"
        +          },
        +          "progression": {
        +            "items": {
        +              "additionalProperties": {},
        +              "properties": {
        +                "count": {
        +                  "maximum": 9007199254740991,
        +                  "minimum": 0,
        +                  "type": "integer"
        +                },
        +                "level": {
        +                  "maximum": 20,
        +                  "minimum": 1,
        +                  "type": "integer"
        +                }
        +              },
        +              "type": "object"
        +            },
        +            "type": "array"
        +          },
        +          "recovery": {
        +            "items": {
        +              "additionalProperties": {},
        +              "properties": {
        +                "count": {
        +                  "maximum": 9007199254740991,
        +                  "minimum": 0,
        +                  "type": "integer"
        +                },
        +                "on": {
        +                  "enum": [
        +                    "Short",
        +                    "Long"
        +                  ],
        +                  "type": "string"
        +                },
        +                "restoreAll": {
        +                  "type": "boolean"
        +                }
        +              },
        +              "type": "object"
        +            },
        +            "type": "array"
        +          }
        +        },
        +        "type": "object"
        +      },
        +      "label": {
        +        "type": "string"
        +      },
        +      "maxLevel": {
        +        "maximum": 9,
        +        "minimum": 0,
        +        "type": "integer"
        +      },
        +      "minLevel": {
        +        "maximum": 9,
        +        "minimum": 0,
        +        "type": "integer"
        +      },
        +      "mode": {
        +        "enum": [
        +          "filter",
        +          "specific"
        +        ],
        +        "type": "string"
        +      },
        +      "prepared": {
        +        "type": "boolean"
        +      },
        +      "progression": {
        +        "items": {
        +          "additionalProperties": {},
        +          "properties": {
        +            "count": {
        +              "maximum": 9007199254740991,
        +              "minimum": 0,
        +              "type": "integer"
        +            },
        +            "level": {
        +              "maximum": 20,
        +              "minimum": 1,
        +              "type": "integer"
        +            }
        +          },
        +          "type": "object"
        +        },
        +        "type": "array"
        +      }
        +    },
        +    "type": "object"
        +  },
        +  "type": "array"
        +}
      • addedInput schema / properties / spellListChoices
        Added value: +{
        +  "items": {
        +    "additionalProperties": {},
        +    "properties": {
        +      "allowedCategories": {
        +        "items": {
        +          "type": "string"
        +        },
        +        "type": "array"
        +      },
        +      "castingAbility": {
        +        "enum": [
        +          "strength",
        +          "dexterity",
        +          "constitution",
        +          "intelligence",
        +          "wisdom",
        +          "charisma"
        +        ],
        +        "type": "string"
        +      },
        +      "castingAbilityOptions": {
        +        "items": {
        +          "enum": [
        +            "strength",
        +            "dexterity",
        +            "constitution",
        +            "intelligence",
        +            "wisdom",
        +            "charisma"
        +          ],
        +          "type": "string"
        +        },
        +        "type": "array"
        +      },
        +      "label": {
        +        "type": "string"
        +      },
        +      "picks": {
        +        "items": {
        +          "additionalProperties": {},
        +          "properties": {
        +            "count": {
        +              "maximum": 9007199254740991,
        +              "minimum": 0,
        +              "type": "integer"
        +            },
        +            "freeCast": {
        +              "additionalProperties": {},
        +              "properties": {
        +                "atWill": {
        +                  "type": "boolean"
        +                },
        +                "count": {
        +                  "maximum": 9007199254740991,
        +                  "minimum": 0,
        +                  "type": "integer"
        +                },
        +                "progression": {
        +                  "items": {
        +                    "additionalProperties": {},
        +                    "properties": {
        +                      "count": {
        +                        "maximum": 9007199254740991,
        +                        "minimum": 0,
        +                        "type": "integer"
        +                      },
        +                      "level": {
        +                        "maximum": 20,
        +                        "minimum": 1,
        +                        "type": "integer"
        +                      }
        +                    },
        +                    "type": "object"
        +                  },
        +                  "type": "array"
        +                },
        +                "recovery": {
        +                  "items": {
        +                    "additionalProperties": {},
        +                    "properties": {
        +                      "count": {
        +                        "maximum": 9007199254740991,
        +                        "minimum": 0,
        +                        "type": "integer"
        +                      },
        +                      "on": {
        +                        "enum": [
        +                          "Short",
        +                          "Long"
        +                        ],
        +                        "type": "string"
        +                      },
        +                      "restoreAll": {
        +                        "type": "boolean"
        +                      }
        +                    },
        +                    "type": "object"
        +                  },
        +                  "type": "array"
        +                }
        +              },
        +              "type": "object"
        +            },
        +            "label": {
        +              "type": "string"
        +            },
        +            "maxLevel": {
        +              "maximum": 9,
        +              "minimum": 0,
        +              "type": "integer"
        +            },
        +            "minLevel": {
        +              "maximum": 9,
        +              "minimum": 0,
        +              "type": "integer"
        +            }
        +          },
        +          "type": "object"
        +        },
        +        "type": "array"
        +      },
        +      "prepared": {
        +        "type": "boolean"
        +      }
        +    },
        +    "type": "object"
        +  },
        +  "type": "array"
        +}
      • addedInput schema / properties / startingEquipment
        Added value: +{
        +  "items": {
        +    "additionalProperties": {},
        +    "properties": {
        +      "items": {
        +        "items": {
        +          "additionalProperties": {},
        +          "properties": {
        +            "_item": {
        +              "description": "Mongo `_id` reference (24-character hex string).",
        +              "minLength": 1,
        +              "type": "string"
        +            },
        +            "quantity": {
        +              "maximum": 9007199254740991,
        +              "minimum": 0,
        +              "type": "integer"
        +            }
        +          },
        +          "type": "object"
        +        },
        +        "type": "array"
        +      },
        +      "label": {
        +        "type": "string"
        +      }
        +    },
        +    "type": "object"
        +  },
        +  "type": "array"
        +}
      • addedInput schema / properties / statBonuses
        Added value: +{
        +  "items": {
        +    "additionalProperties": {},
        +    "properties": {
        +      "attribute": {
        +        "description": "For valueType: 'attribute' — which ability's modifier to use.",
        +        "type": "string"
        +      },
        +      "audience": {
        +        "description": "Who the bonus contributes to. Absent = self.",
        +        "enum": [
        +          "self",
        +          "ally",
        +          "any",
        +          "target",
        +          "enemy"
        +        ],
        +        "type": "string"
        +      },
        +      "dice": {
        +        "description": "For valueType: 'dice' — dice expression (e.g. '1d4').",
        +        "type": "string"
        +      },
        +      "durationCount": {
        +        "description": "Numeric count paired with durationUnit (e.g. count: 3, unit: 'round').",
        +        "maximum": 9007199254740991,
        +        "minimum": 0,
        +        "type": "integer"
        +      },
        +      "durationUnit": {
        +        "description": "How long the bonus persists once fired. Only meaningful for event-driven bonuses.",
        +        "enum": [
        +          "instantaneous",
        +          "untilStartOfNextTurn",
        +          "untilEndOfNextTurn",
        +          "round",
        +          "minute",
        +          "hour",
        +          "untilShortRest",
        +          "untilLongRest"
        +        ],
        +        "type": "string"
        +      },
        +      "fixed": {
        +        "description": "For valueType: 'fixed' — the literal numeric contribution.",
        +        "type": "number"
        +      },
        +      "progression": {
        +        "description": "For valueType: 'byLevel' — per-level rows; walker picks the row with level <= current level.",
        +        "items": {
        +          "additionalProperties": {},
        +          "properties": {
        +            "dice": {
        +              "type": "string"
        +            },
        +            "flat": {
        +              "type": "number"
        +            },
        +            "level": {
        +              "maximum": 20,
        +              "minimum": 1,
        +              "type": "integer"
        +            }
        +          },
        +          "type": "object"
        +        },
        +        "type": "array"
        +      },
        +      "range": {
        +        "description": "Aura radius in feet for ally/any-audience bonuses (Aura of Protection's 10 ft.). Absent = no range filter.",
        +        "maximum": 9007199254740991,
        +        "minimum": 0,
        +        "type": "integer"
        +      },
        +      "requires": {
        +        "description": "Optional predicate list that gates this bonus. Absent / empty = always-on.",
        +        "items": {
        +          "additionalProperties": {},
        +          "properties": {
        +            "armorCategories": {
        +              "description": "For 'equipped' + slot:armor: armor category list (Light / Medium / Heavy). OR semantics — match any.",
        +              "items": {
        +                "type": "string"
        +              },
        +              "type": "array"
        +            },
        +            "condition": {
        +              "description": "For 'condition' predicates: the character-state condition to gate on (5e24 named conditions and ongoing-action states).",
        +              "enum": [
        +                "blinded",
        +                "charmed",
        +                "dazed",
        +                "deafened",
        +                "exhaustion",
        +                "frightened",
        +                "grappled",
        +                "incapacitated",
        +                "invisible",
        +                "paralyzed",
        +                "petrified",
        +                "poisoned",
        +                "prone",
        +                "restrained",
        +                "stunned",
        +                "unconscious",
        +                "concentrating",
        +                "grappling",
        +                "dodging",
        +                "hiding",
        +                "raging"
        +              ],
        +              "type": "string"
        +            },
        +            "equipSlot": {
        +              "description": "Body slot the matched weapon must occupy. mainHand / offHand. Resolved via getRequiredSlots so two-handed grips occupy both.",
        +              "enum": [
        +                "mainHand",
        +                "offHand"
        +              ],
        +              "type": "string"
        +            },
        +            "negate": {
        +              "description": "true inverts the predicate — 'while NOT matching' instead of 'while matching'.",
        +              "type": "boolean"
        +            },
        +            "slot": {
        +              "description": "For 'equipped' predicates: the body category to match (armor / shield / weapon).",
        +              "enum": [
        +                "armor",
        +                "shield",
        +                "weapon"
        +              ],
        +              "type": "string"
        +            },
        +            "type": {
        +              "description": "Predicate type. 'equipped' = character-scoped (gates on what's equipped). 'attackingWeapon' = attack-scoped (gates on the current action's source weapon). 'condition' = gates on a character-state condition.",
        +              "enum": [
        +                "equipped",
        +                "attackingWeapon",
        +                "condition"
        +              ],
        +              "type": "string"
        +            },
        +            "weaponProperties": {
        +              "description": "For 'equipped' + slot:weapon OR 'attackingWeapon': weapon-property list. AND semantics — match all.",
        +              "items": {
        +                "type": "string"
        +              },
        +              "type": "array"
        +            }
        +          },
        +          "type": "object"
        +        },
        +        "type": "array"
        +      },
        +      "requiresLogic": {
        +        "description": "How `requires` predicates compose. 'and' (default) = ALL must hold. 'or' = ANY one is sufficient.",
        +        "enum": [
        +          "and",
        +          "or"
        +        ],
        +        "type": "string"
        +      },
        +      "target": {
        +        "description": "Stat the bonus contributes to (e.g. 'skills.Acrobatics.misc', 'attributes.strength.misc').",
        +        "type": "string"
        +      },
        +      "trigger": {
        +        "description": "Action-economy / cost shape of the bonus. passive / toggled / reaction / perRoll / resource / targetBound.",
        +        "enum": [
        +          "passive",
        +          "toggled",
        +          "reaction",
        +          "perRoll",
        +          "resource",
        +          "targetBound"
        +        ],
        +        "type": "string"
        +      },
        +      "triggerEvent": {
        +        "description": "Game-time event that fires the bonus (onHit / onDamage / startOfYourTurn / etc.). Absent = not event-driven (passive walker contributes whenever `requires` holds).",
        +        "enum": [
        +          "onHit",
        +          "onMiss",
        +          "onDamage",
        +          "startOfYourTurn",
        +          "endOfYourTurn",
        +          "startOfTargetTurn",
        +          "endOfTargetTurn"
        +        ],
        +        "type": "string"
        +      },
        +      "types": {
        +        "description": "Damage type tags for damage.* targets. No-op for non-damage targets.",
        +        "items": {
        +          "type": "string"
        +        },
        +        "type": "array"
        +      },
        +      "valueType": {
        +        "description": "How the contribution is computed. 'fixed' uses `fixed`; 'attribute' uses the mod of `attribute`; 'attackAttribute' uses the action's attack-roll ability (per-attack only); others scale by level/PB/dice.",
        +        "enum": [
        +          "fixed",
        +          "attribute",
        +          "proficiency",
        +          "level",
        +          "halfLevel",
        +          "dice",
        +          "byLevel",
        +          "attackAttribute"
        +        ],
        +        "type": "string"
        +      }
        +    },
        +    "type": "object"
        +  },
        +  "type": "array"
        +}
      • addedInput schema / properties / summary
        Added value: +{
        +  "description": "Short one-line summary.",
        +  "type": "string"
        +}
      • addedInput schema / properties / toolChoices
        Added value: +{
        +  "additionalProperties": {},
        +  "properties": {
        +    "count": {
        +      "maximum": 9007199254740991,
        +      "minimum": 0,
        +      "type": "integer"
        +    },
        +    "options": {
        +      "items": {
        +        "type": "string"
        +      },
        +      "type": "array"
        +    }
        +  },
        +  "type": "object"
        +}
      • addedInput schema / properties / toolProficiencies
        Added value: +{
        +  "items": {
        +    "type": "string"
        +  },
        +  "type": "array"
        +}
      • addedInput schema / properties / type
        Added value: +{
        +  "description": "Rule category. Required at create time; vault rejects without it.",
        +  "enum": [
        +    "Ability",
        +    "Feat",
        +    "Action Card",
        +    "Hindrance",
        +    "Edge",
        +    "Class",
        +    "Background",
        +    "Race",
        +    "Species",
        +    "Ancestry",
        +    "Glossary",
        +    "Stunt",
        +    "Extra"
        +  ],
        +  "type": "string"
        +}
      • addedInput schema / properties / uses
        Added value: +{
        +  "items": {
        +    "additionalProperties": {},
        +    "properties": {
        +      "count": {
        +        "maximum": 9007199254740991,
        +        "minimum": 0,
        +        "type": "integer"
        +      },
        +      "mode": {
        +        "enum": [
        +          "fixed",
        +          "byLevel",
        +          "proficiency"
        +        ],
        +        "type": "string"
        +      },
        +      "name": {
        +        "type": "string"
        +      },
        +      "progression": {
        +        "items": {
        +          "additionalProperties": {},
        +          "properties": {
        +            "count": {
        +              "maximum": 9007199254740991,
        +              "minimum": 0,
        +              "type": "integer"
        +            },
        +            "countAbility": {
        +              "enum": [
        +                "strength",
        +                "dexterity",
        +                "constitution",
        +                "intelligence",
        +                "wisdom",
        +                "charisma"
        +              ],
        +              "type": "string"
        +            },
        +            "countSource": {
        +              "enum": [
        +                "fixed",
        +                "proficiency",
        +                "abilityMod"
        +              ],
        +              "type": "string"
        +            },
        +            "level": {
        +              "maximum": 20,
        +              "minimum": 1,
        +              "type": "integer"
        +            },
        +            "slotLevel": {
        +              "maximum": 9,
        +              "minimum": 1,
        +              "type": "integer"
        +            }
        +          },
        +          "type": "object"
        +        },
        +        "type": "array"
        +      },
        +      "recovery": {
        +        "items": {
        +          "additionalProperties": {},
        +          "properties": {
        +            "count": {
        +              "maximum": 9007199254740991,
        +              "minimum": 0,
        +              "type": "integer"
        +            },
        +            "on": {
        +              "enum": [
        +                "Short",
        +                "Long"
        +              ],
        +              "type": "string"
        +            },
        +            "restoreAll": {
        +              "type": "boolean"
        +            }
        +          },
        +          "type": "object"
        +        },
        +        "type": "array"
        +      },
        +      "rest": {
        +        "enum": [
        +          "Short",
        +          "Long"
        +        ],
        +        "type": "string"
        +      },
        +      "slotLevel": {
        +        "maximum": 9,
        +        "minimum": 1,
        +        "type": "integer"
        +      }
        +    },
        +    "type": "object"
        +  },
        +  "type": "array"
        +}
      • addedInput schema / properties / weaponProficiencies
        Added value: +{
        +  "items": {
        +    "type": "string"
        +  },
        +  "type": "array"
        +}
      • addedInput schema / required
        Added value: +[
        +  "name"
        +]
    • Changedvault_create_spell51 fields changed
      • addedInput schema / $schema
        Added value: +"http://json-schema.org/draft-07/schema#"
      • addedInput schema / additionalProperties
        Added value: +{}
      • addedInput schema / properties / _parent
        Added value: +{
        +  "description": "Parent spell ObjectId for variant spells.",
        +  "minLength": 1,
        +  "type": "string"
        +}
      • addedInput schema / properties / abilityScoreBump
        Added value: +{
        +  "additionalProperties": {},
        +  "properties": {
        +    "options": {
        +      "description": "Alternatives the player picks exactly ONE of (OR).",
        +      "items": {
        +        "additionalProperties": {},
        +        "properties": {
        +          "lines": {
        +            "description": "Lines that ALL apply when this option is chosen (AND).",
        +            "items": {
        +              "additionalProperties": {},
        +              "properties": {
        +                "amount": {
        +                  "description": "How much each chosen ability goes up (usually positive).",
        +                  "type": "number"
        +                },
        +                "count": {
        +                  "description": "How many distinct abilities this line raises.",
        +                  "maximum": 9007199254740991,
        +                  "minimum": 1,
        +                  "type": "integer"
        +                },
        +                "eligible": {
        +                  "description": "Pool to choose from. Empty / absent = any of the six.",
        +                  "items": {
        +                    "enum": [
        +                      "strength",
        +                      "dexterity",
        +                      "constitution",
        +                      "intelligence",
        +                      "wisdom",
        +                      "charisma"
        +                    ],
        +                    "type": "string"
        +                  },
        +                  "type": "array"
        +                },
        +                "max": {
        +                  "description": "Ceiling no chosen score may exceed after the bump (ASI = 20).",
        +                  "maximum": 9007199254740991,
        +                  "minimum": 1,
        +                  "type": "integer"
        +                }
        +              },
        +              "type": "object"
        +            },
        +            "type": "array"
        +          }
        +        },
        +        "type": "object"
        +      },
        +      "type": "array"
        +    }
        +  },
        +  "type": "object"
        +}
      • addedInput schema / properties / abilityScoreSet
        Added value: +{
        +  "items": {
        +    "additionalProperties": {},
        +    "properties": {
        +      "ability": {
        +        "enum": [
        +          "strength",
        +          "dexterity",
        +          "constitution",
        +          "intelligence",
        +          "wisdom",
        +          "charisma"
        +        ],
        +        "type": "string"
        +      },
        +      "value": {
        +        "description": "Score to set the ability to while in effect.",
        +        "maximum": 9007199254740991,
        +        "minimum": 1,
        +        "type": "integer"
        +      }
        +    },
        +    "type": "object"
        +  },
        +  "type": "array"
        +}
      • addedInput schema / properties / actionType
        Added value: +{
        +  "description": "Authoring hint — when set, the character sheet's rule modal shows an 'Add to Actions' button that mints an action row with this `type`.",
        +  "type": "string"
        +}
      • addedInput schema / properties / actions
        Added value: +{
        +  "description": "PF Playtest action-economy marker (F/1/2/3/R).",
        +  "type": "string"
        +}
      • addedInput schema / properties / active
        Added value: +{
        +  "type": "boolean"
        +}
      • addedInput schema / properties / area
        Added value: +{
        +  "additionalProperties": {},
        +  "description": "Area of effect. shape ∈ cone|cube|cylinder|emanation|line|sphere; size (ft); width for line.",
        +  "properties": {
        +    "shape": {
        +      "enum": [
        +        "cone",
        +        "cube",
        +        "cylinder",
        +        "emanation",
        +        "line",
        +        "sphere"
        +      ],
        +      "type": "string"
        +    },
        +    "size": {
        +      "minimum": 0,
        +      "type": "number"
        +    },
        +    "width": {
        +      "minimum": 0,
        +      "type": "number"
        +    }
        +  },
        +  "type": "object"
        +}
      • addedInput schema / properties / castingTime
        Added value: +{
        +  "additionalProperties": {},
        +  "description": "Casting time. unit ∈ action|bonusAction|reaction|minute|hour; count for minute/hour.",
        +  "properties": {
        +    "count": {
        +      "maximum": 9007199254740991,
        +      "minimum": 0,
        +      "type": "integer"
        +    },
        +    "unit": {
        +      "enum": [
        +        "action",
        +        "bonusAction",
        +        "reaction",
        +        "minute",
        +        "hour"
        +      ],
        +      "type": "string"
        +    }
        +  },
        +  "type": "object"
        +}
      • addedInput schema / properties / categories
        Added value: +{
        +  "description": "Go-forward class membership. The field `spellChoices[].allowedCategories` filters on; the vault UI labels it 'Class(es)'. Free-form, taggable.",
        +  "items": {
        +    "type": "string"
        +  },
        +  "type": "array"
        +}
      • addedInput schema / properties / classes
        Added value: +{
        +  "description": "Class-membership list for non-5.5e rulesets (e.g. PFRPG); 5.5e spells use `categories` instead. Free-form per ruleset.",
        +  "items": {
        +    "type": "string"
        +  },
        +  "type": "array"
        +}
      • addedInput schema / properties / components
        Added value: +{
        +  "additionalProperties": {},
        +  "description": "Components: verbal/somatic/material flags, plus material text, gp cost, and consumed flag.",
        +  "properties": {
        +    "material": {
        +      "type": "boolean"
        +    },
        +    "materialConsumed": {
        +      "type": "boolean"
        +    },
        +    "materialCost": {
        +      "minimum": 0,
        +      "type": "number"
        +    },
        +    "materialText": {
        +      "type": "string"
        +    },
        +    "somatic": {
        +      "type": "boolean"
        +    },
        +    "verbal": {
        +      "type": "boolean"
        +    }
        +  },
        +  "type": "object"
        +}
      • addedInput schema / properties / damage
        Added value: +{
        +  "additionalProperties": {},
        +  "properties": {
        +    "appliesTo": {
        +      "enum": [
        +        "melee",
        +        "ranged",
        +        "either"
        +      ],
        +      "type": "string"
        +    },
        +    "area": {
        +      "items": {
        +        "additionalProperties": {},
        +        "properties": {
        +          "shape": {
        +            "enum": [
        +              "cone",
        +              "line",
        +              "sphere",
        +              "cube",
        +              "cylinder",
        +              "emanation",
        +              "radius"
        +            ],
        +            "type": "string"
        +          },
        +          "size": {
        +            "minimum": 0,
        +            "type": "number"
        +          },
        +          "width": {
        +            "minimum": 0,
        +            "type": "number"
        +          }
        +        },
        +        "type": "object"
        +      },
        +      "type": "array"
        +    },
        +    "dice": {
        +      "type": "string"
        +    },
        +    "flat": {
        +      "type": "number"
        +    },
        +    "modifierAbility": {
        +      "enum": [
        +        "strength",
        +        "dexterity",
        +        "constitution",
        +        "intelligence",
        +        "wisdom",
        +        "charisma"
        +      ],
        +      "type": "string"
        +    },
        +    "modifierType": {
        +      "enum": [
        +        "flat",
        +        "proficiency",
        +        "ability"
        +      ],
        +      "type": "string"
        +    },
        +    "onSave": {
        +      "enum": [
        +        "half",
        +        "negates",
        +        "full"
        +      ],
        +      "type": "string"
        +    },
        +    "progression": {
        +      "items": {
        +        "additionalProperties": {},
        +        "properties": {
        +          "dice": {
        +            "type": "string"
        +          },
        +          "flat": {
        +            "type": "number"
        +          },
        +          "level": {
        +            "maximum": 20,
        +            "minimum": 1,
        +            "type": "integer"
        +          }
        +        },
        +        "type": "object"
        +      },
        +      "type": "array"
        +    },
        +    "save": {
        +      "additionalProperties": {},
        +      "properties": {
        +        "ability": {
        +          "enum": [
        +            "none",
        +            "spellcasting",
        +            "attackAttribute",
        +            "strength",
        +            "dexterity",
        +            "constitution",
        +            "intelligence",
        +            "wisdom",
        +            "charisma"
        +          ],
        +          "type": "string"
        +        },
        +        "dcBase": {
        +          "type": "number"
        +        },
        +        "includesProficiency": {
        +          "type": "boolean"
        +        },
        +        "saveType": {
        +          "enum": [
        +            "strength",
        +            "dexterity",
        +            "constitution",
        +            "intelligence",
        +            "wisdom",
        +            "charisma"
        +          ],
        +          "type": "string"
        +        }
        +      },
        +      "type": "object"
        +    },
        +    "scaling": {
        +      "enum": [
        +        "fixed",
        +        "byLevel",
        +        "spellSlot"
        +      ],
        +      "type": "string"
        +    },
        +    "scalingAttribute": {
        +      "type": "string"
        +    },
        +    "slotIncrement": {
        +      "additionalProperties": {},
        +      "properties": {
        +        "dice": {
        +          "type": "string"
        +        },
        +        "flat": {
        +          "type": "number"
        +        },
        +        "targets": {
        +          "maximum": 9007199254740991,
        +          "minimum": 1,
        +          "type": "integer"
        +        }
        +      },
        +      "type": "object"
        +    },
        +    "targets": {
        +      "additionalProperties": {},
        +      "properties": {
        +        "count": {
        +          "maximum": 9007199254740991,
        +          "minimum": 1,
        +          "type": "integer"
        +        }
        +      },
        +      "type": "object"
        +    },
        +    "trigger": {
        +      "enum": [
        +        "passive",
        +        "toggled",
        +        "reaction",
        +        "perRoll",
        +        "resource",
        +        "targetBound"
        +      ],
        +      "type": "string"
        +    },
        +    "types": {
        +      "items": {
        +        "type": "string"
        +      },
        +      "type": "array"
        +    }
        +  },
        +  "type": "object"
        +}
      • addedInput schema / properties / damageReduction
        Added value: +{
        +  "items": {
        +    "additionalProperties": {},
        +    "properties": {
        +      "amount": {
        +        "additionalProperties": {},
        +        "properties": {
        +          "dice": {
        +            "type": "string"
        +          },
        +          "flat": {
        +            "type": "number"
        +          },
        +          "includesProficiency": {
        +            "type": "boolean"
        +          },
        +          "modifierSource": {
        +            "enum": [
        +              "spellcasting",
        +              "attackAttribute",
        +              "strength",
        +              "dexterity",
        +              "constitution",
        +              "intelligence",
        +              "wisdom",
        +              "charisma"
        +            ],
        +            "type": "string"
        +          }
        +        },
        +        "type": "object"
        +      },
        +      "range": {
        +        "maximum": 9007199254740991,
        +        "minimum": 0,
        +        "type": "integer"
        +      },
        +      "requires": {
        +        "items": {
        +          "additionalProperties": {},
        +          "properties": {
        +            "armorCategories": {
        +              "description": "For 'equipped' + slot:armor: armor category list (Light / Medium / Heavy). OR semantics — match any.",
        +              "items": {
        +                "type": "string"
        +              },
        +              "type": "array"
        +            },
        +            "condition": {
        +              "description": "For 'condition' predicates: the character-state condition to gate on (5e24 named conditions and ongoing-action states).",
        +              "enum": [
        +                "blinded",
        +                "charmed",
        +                "dazed",
        +                "deafened",
        +                "exhaustion",
        +                "frightened",
        +                "grappled",
        +                "incapacitated",
        +                "invisible",
        +                "paralyzed",
        +                "petrified",
        +                "poisoned",
        +                "prone",
        +                "restrained",
        +                "stunned",
        +                "unconscious",
        +                "concentrating",
        +                "grappling",
        +                "dodging",
        +                "hiding",
        +                "raging"
        +              ],
        +              "type": "string"
        +            },
        +            "equipSlot": {
        +              "description": "Body slot the matched weapon must occupy. mainHand / offHand. Resolved via getRequiredSlots so two-handed grips occupy both.",
        +              "enum": [
        +                "mainHand",
        +                "offHand"
        +              ],
        +              "type": "string"
        +            },
        +            "negate": {
        +              "description": "true inverts the predicate — 'while NOT matching' instead of 'while matching'.",
        +              "type": "boolean"
        +            },
        +            "slot": {
        +              "description": "For 'equipped' predicates: the body category to match (armor / shield / weapon).",
        +              "enum": [
        +                "armor",
        +                "shield",
        +                "weapon"
        +              ],
        +              "type": "string"
        +            },
        +            "type": {
        +              "description": "Predicate type. 'equipped' = character-scoped (gates on what's equipped). 'attackingWeapon' = attack-scoped (gates on the current action's source weapon). 'condition' = gates on a character-state condition.",
        +              "enum": [
        +                "equipped",
        +                "attackingWeapon",
        +                "condition"
        +              ],
        +              "type": "string"
        +            },
        +            "weaponProperties": {
        +              "description": "For 'equipped' + slot:weapon OR 'attackingWeapon': weapon-property list. AND semantics — match all.",
        +              "items": {
        +                "type": "string"
        +              },
        +              "type": "array"
        +            }
        +          },
        +          "type": "object"
        +        },
        +        "type": "array"
        +      },
        +      "requiresLogic": {
        +        "enum": [
        +          "and",
        +          "or"
        +        ],
        +        "type": "string"
        +      },
        +      "target": {
        +        "enum": [
        +          "self",
        +          "ally",
        +          "any",
        +          "target",
        +          "enemy"
        +        ],
        +        "type": "string"
        +      },
        +      "trigger": {
        +        "enum": [
        +          "passive",
        +          "toggled",
        +          "reaction",
        +          "perRoll",
        +          "resource",
        +          "targetBound"
        +        ],
        +        "type": "string"
        +      },
        +      "types": {
        +        "items": {
        +          "type": "string"
        +        },
        +        "type": "array"
        +      }
        +    },
        +    "type": "object"
        +  },
        +  "type": "array"
        +}
      • addedInput schema / properties / description
        Added value: +{
        +  "description": "Full spell body. Markdown is supported.",
        +  "type": "string"
        +}
      • addedInput schema / properties / diceFloors
        Added value: +{
        +  "items": {
        +    "additionalProperties": {},
        +    "properties": {
        +      "appliesTo": {
        +        "enum": [
        +          "damage",
        +          "damage.melee",
        +          "damage.ranged",
        +          "damage.spell",
        +          "healing"
        +        ],
        +        "type": "string"
        +      },
        +      "floor": {
        +        "maximum": 9007199254740991,
        +        "minimum": 1,
        +        "type": "integer"
        +      },
        +      "requires": {
        +        "items": {
        +          "additionalProperties": {},
        +          "properties": {
        +            "armorCategories": {
        +              "description": "For 'equipped' + slot:armor: armor category list (Light / Medium / Heavy). OR semantics — match any.",
        +              "items": {
        +                "type": "string"
        +              },
        +              "type": "array"
        +            },
        +            "condition": {
        +              "description": "For 'condition' predicates: the character-state condition to gate on (5e24 named conditions and ongoing-action states).",
        +              "enum": [
        +                "blinded",
        +                "charmed",
        +                "dazed",
        +                "deafened",
        +                "exhaustion",
        +                "frightened",
        +                "grappled",
        +                "incapacitated",
        +                "invisible",
        +                "paralyzed",
        +                "petrified",
        +                "poisoned",
        +                "prone",
        +                "restrained",
        +                "stunned",
        +                "unconscious",
        +                "concentrating",
        +                "grappling",
        +                "dodging",
        +                "hiding",
        +                "raging"
        +              ],
        +              "type": "string"
        +            },
        +            "equipSlot": {
        +              "description": "Body slot the matched weapon must occupy. mainHand / offHand. Resolved via getRequiredSlots so two-handed grips occupy both.",
        +              "enum": [
        +                "mainHand",
        +                "offHand"
        +              ],
        +              "type": "string"
        +            },
        +            "negate": {
        +              "description": "true inverts the predicate — 'while NOT matching' instead of 'while matching'.",
        +              "type": "boolean"
        +            },
        +            "slot": {
        +              "description": "For 'equipped' predicates: the body category to match (armor / shield / weapon).",
        +              "enum": [
        +                "armor",
        +                "shield",
        +                "weapon"
        +              ],
        +              "type": "string"
        +            },
        +            "type": {
        +              "description": "Predicate type. 'equipped' = character-scoped (gates on what's equipped). 'attackingWeapon' = attack-scoped (gates on the current action's source weapon). 'condition' = gates on a character-state condition.",
        +              "enum": [
        +                "equipped",
        +                "attackingWeapon",
        +                "condition"
        +              ],
        +              "type": "string"
        +            },
        +            "weaponProperties": {
        +              "description": "For 'equipped' + slot:weapon OR 'attackingWeapon': weapon-property list. AND semantics — match all.",
        +              "items": {
        +                "type": "string"
        +              },
        +              "type": "array"
        +            }
        +          },
        +          "type": "object"
        +        },
        +        "type": "array"
        +      },
        +      "requiresLogic": {
        +        "enum": [
        +          "and",
        +          "or"
        +        ],
        +        "type": "string"
        +      },
        +      "threshold": {
        +        "maximum": 9007199254740991,
        +        "minimum": 1,
        +        "type": "integer"
        +      },
        +      "trigger": {
        +        "enum": [
        +          "passive",
        +          "toggled",
        +          "reaction",
        +          "perRoll",
        +          "resource",
        +          "targetBound"
        +        ],
        +        "type": "string"
        +      }
        +    },
        +    "type": "object"
        +  },
        +  "type": "array"
        +}
      • addedInput schema / properties / diceReplacements
        Added value: +{
        +  "items": {
        +    "additionalProperties": {},
        +    "properties": {
        +      "_target": {
        +        "description": "Mongo `_id` reference (24-character hex string).",
        +        "minLength": 1,
        +        "type": "string"
        +      },
        +      "dice": {
        +        "type": "string"
        +      },
        +      "progression": {
        +        "items": {
        +          "additionalProperties": {},
        +          "properties": {
        +            "dice": {
        +              "type": "string"
        +            },
        +            "level": {
        +              "maximum": 20,
        +              "minimum": 1,
        +              "type": "integer"
        +            }
        +          },
        +          "type": "object"
        +        },
        +        "type": "array"
        +      },
        +      "requires": {
        +        "items": {
        +          "additionalProperties": {},
        +          "properties": {
        +            "armorCategories": {
        +              "description": "For 'equipped' + slot:armor: armor category list (Light / Medium / Heavy). OR semantics — match any.",
        +              "items": {
        +                "type": "string"
        +              },
        +              "type": "array"
        +            },
        +            "condition": {
        +              "description": "For 'condition' predicates: the character-state condition to gate on (5e24 named conditions and ongoing-action states).",
        +              "enum": [
        +                "blinded",
        +                "charmed",
        +                "dazed",
        +                "deafened",
        +                "exhaustion",
        +                "frightened",
        +                "grappled",
        +                "incapacitated",
        +                "invisible",
        +                "paralyzed",
        +                "petrified",
        +                "poisoned",
        +                "prone",
        +                "restrained",
        +                "stunned",
        +                "unconscious",
        +                "concentrating",
        +                "grappling",
        +                "dodging",
        +                "hiding",
        +                "raging"
        +              ],
        +              "type": "string"
        +            },
        +            "equipSlot": {
        +              "description": "Body slot the matched weapon must occupy. mainHand / offHand. Resolved via getRequiredSlots so two-handed grips occupy both.",
        +              "enum": [
        +                "mainHand",
        +                "offHand"
        +              ],
        +              "type": "string"
        +            },
        +            "negate": {
        +              "description": "true inverts the predicate — 'while NOT matching' instead of 'while matching'.",
        +              "type": "boolean"
        +            },
        +            "slot": {
        +              "description": "For 'equipped' predicates: the body category to match (armor / shield / weapon).",
        +              "enum": [
        +                "armor",
        +                "shield",
        +                "weapon"
        +              ],
        +              "type": "string"
        +            },
        +            "type": {
        +              "description": "Predicate type. 'equipped' = character-scoped (gates on what's equipped). 'attackingWeapon' = attack-scoped (gates on the current action's source weapon). 'condition' = gates on a character-state condition.",
        +              "enum": [
        +                "equipped",
        +                "attackingWeapon",
        +                "condition"
        +              ],
        +              "type": "string"
        +            },
        +            "weaponProperties": {
        +              "description": "For 'equipped' + slot:weapon OR 'attackingWeapon': weapon-property list. AND semantics — match all.",
        +              "items": {
        +                "type": "string"
        +              },
        +              "type": "array"
        +            }
        +          },
        +          "type": "object"
        +        },
        +        "type": "array"
        +      },
        +      "requiresLogic": {
        +        "enum": [
        +          "and",
        +          "or"
        +        ],
        +        "type": "string"
        +      }
        +    },
        +    "type": "object"
        +  },
        +  "type": "array"
        +}
      • addedInput schema / properties / duration
        Added value: +{
        +  "additionalProperties": {},
        +  "description": "Spell duration. unit ∈ instantaneous | round | minute | hour | day | untilDispelled | untilDispelledOrTriggered | special; count for timed units; concentration flag; upTo flag for a non-concentration capped duration (\"Up to 1 minute\").",
        +  "properties": {
        +    "concentration": {
        +      "type": "boolean"
        +    },
        +    "count": {
        +      "maximum": 9007199254740991,
        +      "minimum": 0,
        +      "type": "integer"
        +    },
        +    "unit": {
        +      "enum": [
        +        "instantaneous",
        +        "round",
        +        "minute",
        +        "hour",
        +        "day",
        +        "untilDispelled",
        +        "untilDispelledOrTriggered",
        +        "special"
        +      ],
        +      "type": "string"
        +    },
        +    "upTo": {
        +      "type": "boolean"
        +    }
        +  },
        +  "type": "object"
        +}
      • addedInput schema / properties / effect
        Added value: +{
        +  "additionalProperties": {},
        +  "properties": {
        +    "audience": {
        +      "enum": [
        +        "self",
        +        "ally",
        +        "any",
        +        "target",
        +        "enemy"
        +      ],
        +      "type": "string"
        +    },
        +    "conditions": {
        +      "items": {
        +        "additionalProperties": {},
        +        "properties": {
        +          "applyWhen": {
        +            "enum": [
        +              "always",
        +              "onFail",
        +              "onSuccess"
        +            ],
        +            "type": "string"
        +          },
        +          "durationCount": {
        +            "maximum": 9007199254740991,
        +            "minimum": 0,
        +            "type": "integer"
        +          },
        +          "durationUnit": {
        +            "enum": [
        +              "round",
        +              "minute",
        +              "hour",
        +              "day",
        +              "untilShortRest",
        +              "untilLongRest",
        +              "special"
        +            ],
        +            "type": "string"
        +          },
        +          "name": {
        +            "type": "string"
        +          },
        +          "target": {
        +            "enum": [
        +              "self",
        +              "target"
        +            ],
        +            "type": "string"
        +          }
        +        },
        +        "type": "object"
        +      },
        +      "type": "array"
        +    },
        +    "save": {
        +      "additionalProperties": {},
        +      "properties": {
        +        "ability": {
        +          "enum": [
        +            "none",
        +            "spellcasting",
        +            "attackAttribute",
        +            "strength",
        +            "dexterity",
        +            "constitution",
        +            "intelligence",
        +            "wisdom",
        +            "charisma"
        +          ],
        +          "type": "string"
        +        },
        +        "dcBase": {
        +          "type": "number"
        +        },
        +        "includesProficiency": {
        +          "type": "boolean"
        +        },
        +        "saveType": {
        +          "enum": [
        +            "strength",
        +            "dexterity",
        +            "constitution",
        +            "intelligence",
        +            "wisdom",
        +            "charisma"
        +          ],
        +          "type": "string"
        +        }
        +      },
        +      "type": "object"
        +    },
        +    "triggerEvent": {
        +      "enum": [
        +        "onHit",
        +        "onMiss",
        +        "onDamage",
        +        "startOfYourTurn",
        +        "endOfYourTurn",
        +        "startOfTargetTurn",
        +        "endOfTargetTurn"
        +      ],
        +      "type": "string"
        +    }
        +  },
        +  "type": "object"
        +}
      • addedInput schema / properties / forcedMovement
        Added value: +{
        +  "items": {
        +    "additionalProperties": {},
        +    "properties": {
        +      "audience": {
        +        "enum": [
        +          "self",
        +          "ally",
        +          "any",
        +          "target",
        +          "enemy"
        +        ],
        +        "type": "string"
        +      },
        +      "direction": {
        +        "enum": [
        +          "awayFromSelf",
        +          "towardSelf",
        +          "anywhere"
        +        ],
        +        "type": "string"
        +      },
        +      "distance": {
        +        "maximum": 9007199254740991,
        +        "minimum": 0,
        +        "type": "integer"
        +      },
        +      "maxTargetSize": {
        +        "enum": [
        +          "tiny",
        +          "small",
        +          "medium",
        +          "large",
        +          "huge",
        +          "gargantuan"
        +        ],
        +        "type": "string"
        +      },
        +      "requires": {
        +        "items": {
        +          "additionalProperties": {},
        +          "properties": {
        +            "armorCategories": {
        +              "description": "For 'equipped' + slot:armor: armor category list (Light / Medium / Heavy). OR semantics — match any.",
        +              "items": {
        +                "type": "string"
        +              },
        +              "type": "array"
        +            },
        +            "condition": {
        +              "description": "For 'condition' predicates: the character-state condition to gate on (5e24 named conditions and ongoing-action states).",
        +              "enum": [
        +                "blinded",
        +                "charmed",
        +                "dazed",
        +                "deafened",
        +                "exhaustion",
        +                "frightened",
        +                "grappled",
        +                "incapacitated",
        +                "invisible",
        +                "paralyzed",
        +                "petrified",
        +                "poisoned",
        +                "prone",
        +                "restrained",
        +                "stunned",
        +                "unconscious",
        +                "concentrating",
        +                "grappling",
        +                "dodging",
        +                "hiding",
        +                "raging"
        +              ],
        +              "type": "string"
        +            },
        +            "equipSlot": {
        +              "description": "Body slot the matched weapon must occupy. mainHand / offHand. Resolved via getRequiredSlots so two-handed grips occupy both.",
        +              "enum": [
        +                "mainHand",
        +                "offHand"
        +              ],
        +              "type": "string"
        +            },
        +            "negate": {
        +              "description": "true inverts the predicate — 'while NOT matching' instead of 'while matching'.",
        +              "type": "boolean"
        +            },
        +            "slot": {
        +              "description": "For 'equipped' predicates: the body category to match (armor / shield / weapon).",
        +              "enum": [
        +                "armor",
        +                "shield",
        +                "weapon"
        +              ],
        +              "type": "string"
        +            },
        +            "type": {
        +              "description": "Predicate type. 'equipped' = character-scoped (gates on what's equipped). 'attackingWeapon' = attack-scoped (gates on the current action's source weapon). 'condition' = gates on a character-state condition.",
        +              "enum": [
        +                "equipped",
        +                "attackingWeapon",
        +                "condition"
        +              ],
        +              "type": "string"
        +            },
        +            "weaponProperties": {
        +              "description": "For 'equipped' + slot:weapon OR 'attackingWeapon': weapon-property list. AND semantics — match all.",
        +              "items": {
        +                "type": "string"
        +              },
        +              "type": "array"
        +            }
        +          },
        +          "type": "object"
        +        },
        +        "type": "array"
        +      },
        +      "requiresLogic": {
        +        "enum": [
        +          "and",
        +          "or"
        +        ],
        +        "type": "string"
        +      },
        +      "triggerEvent": {
        +        "enum": [
        +          "onHit",
        +          "onMiss",
        +          "onDamage",
        +          "startOfYourTurn",
        +          "endOfYourTurn",
        +          "startOfTargetTurn",
        +          "endOfTargetTurn"
        +        ],
        +        "type": "string"
        +      }
        +    },
        +    "type": "object"
        +  },
        +  "type": "array"
        +}
      • addedInput schema / properties / healing
        Added value: +{
        +  "additionalProperties": {},
        +  "properties": {
        +    "dice": {
        +      "type": "string"
        +    },
        +    "flat": {
        +      "type": "number"
        +    },
        +    "modifierSource": {
        +      "enum": [
        +        "level",
        +        "spellcasting",
        +        "strength",
        +        "dexterity",
        +        "constitution",
        +        "intelligence",
        +        "wisdom",
        +        "charisma"
        +      ],
        +      "type": "string"
        +    },
        +    "progression": {
        +      "items": {
        +        "additionalProperties": {},
        +        "properties": {
        +          "dice": {
        +            "type": "string"
        +          },
        +          "flat": {
        +            "type": "number"
        +          },
        +          "level": {
        +            "maximum": 20,
        +            "minimum": 1,
        +            "type": "integer"
        +          }
        +        },
        +        "type": "object"
        +      },
        +      "type": "array"
        +    },
        +    "scaling": {
        +      "enum": [
        +        "fixed",
        +        "byLevel",
        +        "proficiency",
        +        "spellSlot"
        +      ],
        +      "type": "string"
        +    },
        +    "slotIncrement": {
        +      "additionalProperties": {},
        +      "properties": {
        +        "dice": {
        +          "type": "string"
        +        },
        +        "flat": {
        +          "type": "number"
        +        }
        +      },
        +      "type": "object"
        +    },
        +    "target": {
        +      "enum": [
        +        "self",
        +        "ally",
        +        "any",
        +        "multiple"
        +      ],
        +      "type": "string"
        +    },
        +    "targets": {
        +      "additionalProperties": {},
        +      "properties": {
        +        "count": {
        +          "maximum": 9007199254740991,
        +          "minimum": 1,
        +          "type": "integer"
        +        }
        +      },
        +      "type": "object"
        +    }
        +  },
        +  "type": "object"
        +}
      • addedInput schema / properties / higherLevel
        Added value: +{
        +  "description": "Higher-Level / cantrip-scaling text (what changes when cast with a higher slot).",
        +  "type": "string"
        +}
      • addedInput schema / properties / level
        Added value: +{
        +  "description": "Spell level. 0 for cantrips; 1–9 for leveled spells (5e/5e24).",
        +  "maximum": 9007199254740991,
        +  "minimum": -9007199254740991,
        +  "type": "integer"
        +}
      • addedInput schema / properties / mechanicsKey
        Added value: +{
        +  "type": "string"
        +}
      • addedInput schema / properties / name
        Added value: +{
        +  "description": "Display name. Required.",
        +  "minLength": 1,
        +  "type": "string"
        +}
      • addedInput schema / properties / ogl
        Added value: +{
        +  "type": "boolean"
        +}
      • addedInput schema / properties / parameters
        Added value: +{
        +  "items": {
        +    "additionalProperties": {},
        +    "properties": {
        +      "label": {
        +        "type": "string"
        +      },
        +      "max": {
        +        "type": "number"
        +      },
        +      "min": {
        +        "type": "number"
        +      },
        +      "name": {
        +        "type": "string"
        +      },
        +      "type": {
        +        "enum": [
        +          "number",
        +          "string",
        +          "enum"
        +        ],
        +        "type": "string"
        +      },
        +      "unit": {
        +        "type": "string"
        +      }
        +    },
        +    "type": "object"
        +  },
        +  "type": "array"
        +}
      • addedInput schema / properties / preparedSpells
        Added value: +{
        +  "additionalProperties": {},
        +  "properties": {
        +    "count": {
        +      "maximum": 9007199254740991,
        +      "minimum": 0,
        +      "type": "integer"
        +    },
        +    "progression": {
        +      "items": {
        +        "additionalProperties": {},
        +        "properties": {
        +          "count": {
        +            "maximum": 9007199254740991,
        +            "minimum": 0,
        +            "type": "integer"
        +          },
        +          "level": {
        +            "maximum": 20,
        +            "minimum": 1,
        +            "type": "integer"
        +          }
        +        },
        +        "type": "object"
        +      },
        +      "type": "array"
        +    }
        +  },
        +  "type": "object"
        +}
      • addedInput schema / properties / prerequisites
        Added value: +{
        +  "items": {
        +    "additionalProperties": {},
        +    "properties": {
        +      "abilities": {
        +        "description": "For abilityScore: ANY listed ability meeting `min` satisfies ('Str or Dex 13+').",
        +        "items": {
        +          "enum": [
        +            "strength",
        +            "dexterity",
        +            "constitution",
        +            "intelligence",
        +            "wisdom",
        +            "charisma"
        +          ],
        +          "type": "string"
        +        },
        +        "type": "array"
        +      },
        +      "category": {
        +        "description": "For rule (filter): matches any held rule in this category.",
        +        "type": "string"
        +      },
        +      "class": {
        +        "description": "For a `level` predicate: a Class rule id that scopes `min` to 'Nth level in that class'. Absent = total character level.",
        +        "minLength": 1,
        +        "type": "string"
        +      },
        +      "min": {
        +        "description": "Numeric minimum — character level (level), class level (class), or ability score (abilityScore).",
        +        "maximum": 9007199254740991,
        +        "minimum": 0,
        +        "type": "integer"
        +      },
        +      "negate": {
        +        "description": "true inverts the predicate — 'must NOT meet this'.",
        +        "type": "boolean"
        +      },
        +      "proficiency": {
        +        "description": "For proficiency: the proficiency name (e.g. 'Martial', 'Stealth').",
        +        "type": "string"
        +      },
        +      "proficiencyType": {
        +        "description": "For proficiency: the family.",
        +        "enum": [
        +          "skill",
        +          "tool",
        +          "weapon",
        +          "armor",
        +          "save",
        +          "language"
        +        ],
        +        "type": "string"
        +      },
        +      "rule": {
        +        "description": "For rule: a specific held Rule id.",
        +        "minLength": 1,
        +        "type": "string"
        +      },
        +      "ruleType": {
        +        "description": "For rule (filter): matches any held rule of this type.",
        +        "type": "string"
        +      },
        +      "spell": {
        +        "description": "For spell: a specific known Spell id.",
        +        "minLength": 1,
        +        "type": "string"
        +      },
        +      "spellList": {
        +        "description": "For spell (filter): knows any spell from this class list.",
        +        "type": "string"
        +      },
        +      "type": {
        +        "description": "Predicate kind: level / abilityScore / rule / spell / proficiency / spellcasting. (A class is required via a `rule` predicate pointing at the class rule.)",
        +        "enum": [
        +          "level",
        +          "abilityScore",
        +          "rule",
        +          "spell",
        +          "proficiency",
        +          "spellcasting"
        +        ],
        +        "type": "string"
        +      }
        +    },
        +    "type": "object"
        +  },
        +  "type": "array"
        +}
      • addedInput schema / properties / prerequisitesLogic
        Added value: +{
        +  "enum": [
        +    "and",
        +    "or"
        +  ],
        +  "type": "string"
        +}
      • addedInput schema / properties / proficiencyChoices
        Added value: +{
        +  "items": {
        +    "additionalProperties": {},
        +    "properties": {
        +      "allowedItems": {
        +        "items": {
        +          "type": "string"
        +        },
        +        "type": "array"
        +      },
        +      "level": {
        +        "enum": [
        +          "proficient",
        +          "expertise"
        +        ],
        +        "type": "string"
        +      },
        +      "mode": {
        +        "enum": [
        +          "specific",
        +          "all"
        +        ],
        +        "type": "string"
        +      },
        +      "progression": {
        +        "items": {
        +          "additionalProperties": {},
        +          "properties": {
        +            "count": {
        +              "maximum": 9007199254740991,
        +              "minimum": 0,
        +              "type": "integer"
        +            },
        +            "level": {
        +              "maximum": 20,
        +              "minimum": 1,
        +              "type": "integer"
        +            }
        +          },
        +          "type": "object"
        +        },
        +        "type": "array"
        +      },
        +      "types": {
        +        "items": {
        +          "enum": [
        +            "skill",
        +            "tool",
        +            "save",
        +            "weapon",
        +            "armor",
        +            "language"
        +          ],
        +          "type": "string"
        +        },
        +        "type": "array"
        +      }
        +    },
        +    "type": "object"
        +  },
        +  "type": "array"
        +}
      • addedInput schema / properties / publisher
        Added value: +{
        +  "type": "string"
        +}
      • addedInput schema / properties / range
        Added value: +{
        +  "additionalProperties": {},
        +  "description": "Range. kind ∈ self|touch|ranged|sight|unlimited|special; distance for ranged; unit ∈ feet|miles (default feet).",
        +  "properties": {
        +    "distance": {
        +      "minimum": 0,
        +      "type": "number"
        +    },
        +    "kind": {
        +      "enum": [
        +        "self",
        +        "touch",
        +        "ranged",
        +        "sight",
        +        "unlimited",
        +        "special"
        +      ],
        +      "type": "string"
        +    },
        +    "unit": {
        +      "enum": [
        +        "feet",
        +        "miles"
        +      ],
        +      "type": "string"
        +    }
        +  },
        +  "type": "object"
        +}
      • addedInput schema / properties / rank
        Added value: +{
        +  "description": "PFRPG2 rank field. Free-form.",
        +  "type": "string"
        +}
      • addedInput schema / properties / reactionTrigger
        Added value: +{
        +  "description": "When castingTime.unit is 'reaction', the trigger text ('which you take when…').",
        +  "type": "string"
        +}
      • addedInput schema / properties / recurringDamage
        Added value: +{
        +  "items": {
        +    "additionalProperties": {},
        +    "properties": {
        +      "amount": {
        +        "additionalProperties": {},
        +        "properties": {
        +          "dice": {
        +            "type": "string"
        +          },
        +          "flat": {
        +            "type": "number"
        +          },
        +          "includesProficiency": {
        +            "type": "boolean"
        +          },
        +          "modifierSource": {
        +            "enum": [
        +              "spellcasting",
        +              "attackAttribute",
        +              "strength",
        +              "dexterity",
        +              "constitution",
        +              "intelligence",
        +              "wisdom",
        +              "charisma"
        +            ],
        +            "type": "string"
        +          }
        +        },
        +        "type": "object"
        +      },
        +      "audience": {
        +        "enum": [
        +          "self",
        +          "ally",
        +          "any",
        +          "target",
        +          "enemy"
        +        ],
        +        "type": "string"
        +      },
        +      "durationCount": {
        +        "maximum": 9007199254740991,
        +        "minimum": 0,
        +        "type": "integer"
        +      },
        +      "durationUnit": {
        +        "enum": [
        +          "instantaneous",
        +          "untilStartOfNextTurn",
        +          "untilEndOfNextTurn",
        +          "round",
        +          "minute",
        +          "hour",
        +          "untilShortRest",
        +          "untilLongRest"
        +        ],
        +        "type": "string"
        +      },
        +      "ignoreResistances": {
        +        "type": "boolean"
        +      },
        +      "inheritDamageType": {
        +        "type": "boolean"
        +      },
        +      "range": {
        +        "maximum": 9007199254740991,
        +        "minimum": 0,
        +        "type": "integer"
        +      },
        +      "requires": {
        +        "items": {
        +          "additionalProperties": {},
        +          "properties": {
        +            "armorCategories": {
        +              "description": "For 'equipped' + slot:armor: armor category list (Light / Medium / Heavy). OR semantics — match any.",
        +              "items": {
        +                "type": "string"
        +              },
        +              "type": "array"
        +            },
        +            "condition": {
        +              "description": "For 'condition' predicates: the character-state condition to gate on (5e24 named conditions and ongoing-action states).",
        +              "enum": [
        +                "blinded",
        +                "charmed",
        +                "dazed",
        +                "deafened",
        +                "exhaustion",
        +                "frightened",
        +                "grappled",
        +                "incapacitated",
        +                "invisible",
        +                "paralyzed",
        +                "petrified",
        +                "poisoned",
        +                "prone",
        +                "restrained",
        +                "stunned",
        +                "unconscious",
        +                "concentrating",
        +                "grappling",
        +                "dodging",
        +                "hiding",
        +                "raging"
        +              ],
        +              "type": "string"
        +            },
        +            "equipSlot": {
        +              "description": "Body slot the matched weapon must occupy. mainHand / offHand. Resolved via getRequiredSlots so two-handed grips occupy both.",
        +              "enum": [
        +                "mainHand",
        +                "offHand"
        +              ],
        +              "type": "string"
        +            },
        +            "negate": {
        +              "description": "true inverts the predicate — 'while NOT matching' instead of 'while matching'.",
        +              "type": "boolean"
        +            },
        +            "slot": {
        +              "description": "For 'equipped' predicates: the body category to match (armor / shield / weapon).",
        +              "enum": [
        +                "armor",
        +                "shield",
        +                "weapon"
        +              ],
        +              "type": "string"
        +            },
        +            "type": {
        +              "description": "Predicate type. 'equipped' = character-scoped (gates on what's equipped). 'attackingWeapon' = attack-scoped (gates on the current action's source weapon). 'condition' = gates on a character-state condition.",
        +              "enum": [
        +                "equipped",
        +                "attackingWeapon",
        +                "condition"
        +              ],
        +              "type": "string"
        +            },
        +            "weaponProperties": {
        +              "description": "For 'equipped' + slot:weapon OR 'attackingWeapon': weapon-property list. AND semantics — match all.",
        +              "items": {
        +                "type": "string"
        +              },
        +              "type": "array"
        +            }
        +          },
        +          "type": "object"
        +        },
        +        "type": "array"
        +      },
        +      "requiresLogic": {
        +        "enum": [
        +          "and",
        +          "or"
        +        ],
        +        "type": "string"
        +      },
        +      "triggerEvent": {
        +        "enum": [
        +          "startOfYourTurn",
        +          "endOfYourTurn",
        +          "startOfTargetTurn",
        +          "endOfTargetTurn",
        +          "whenTargetEntersArea",
        +          "onHit",
        +          "onMiss",
        +          "onDamage"
        +        ],
        +        "type": "string"
        +      },
        +      "types": {
        +        "items": {
        +          "type": "string"
        +        },
        +        "type": "array"
        +      }
        +    },
        +    "type": "object"
        +  },
        +  "type": "array"
        +}
      • addedInput schema / properties / resistances
        Added value: +{
        +  "items": {
        +    "additionalProperties": {},
        +    "properties": {
        +      "mode": {
        +        "enum": [
        +          "resistance",
        +          "immunity",
        +          "vulnerability"
        +        ],
        +        "type": "string"
        +      },
        +      "range": {
        +        "description": "Aura radius in feet for ally/any-targeted resistances (Warding Aura's 10 ft.). Absent = self-only.",
        +        "maximum": 9007199254740991,
        +        "minimum": 0,
        +        "type": "integer"
        +      },
        +      "target": {
        +        "description": "Who the resistance protects — mirrors damageReduction's target/range pair. Absent = self.",
        +        "enum": [
        +          "self",
        +          "ally",
        +          "any",
        +          "target",
        +          "enemy"
        +        ],
        +        "type": "string"
        +      },
        +      "trigger": {
        +        "enum": [
        +          "passive",
        +          "toggled",
        +          "reaction",
        +          "perRoll",
        +          "resource",
        +          "targetBound"
        +        ],
        +        "type": "string"
        +      },
        +      "types": {
        +        "items": {
        +          "type": "string"
        +        },
        +        "type": "array"
        +      }
        +    },
        +    "type": "object"
        +  },
        +  "type": "array"
        +}
      • addedInput schema / properties / ritual
        Added value: +{
        +  "description": "5.5e ritual tag — the spell can be cast as a ritual (no spell slot).",
        +  "type": "boolean"
        +}
      • addedInput schema / properties / rollMods
        Added value: +{
        +  "items": {
        +    "additionalProperties": {},
        +    "properties": {
        +      "audience": {
        +        "enum": [
        +          "self",
        +          "ally",
        +          "any",
        +          "target",
        +          "enemy"
        +        ],
        +        "type": "string"
        +      },
        +      "consumeOnUse": {
        +        "type": "boolean"
        +      },
        +      "durationCount": {
        +        "maximum": 9007199254740991,
        +        "minimum": 0,
        +        "type": "integer"
        +      },
        +      "durationUnit": {
        +        "enum": [
        +          "instantaneous",
        +          "untilStartOfNextTurn",
        +          "untilEndOfNextTurn",
        +          "round",
        +          "minute",
        +          "hour",
        +          "untilShortRest",
        +          "untilLongRest"
        +        ],
        +        "type": "string"
        +      },
        +      "mode": {
        +        "enum": [
        +          "advantage",
        +          "disadvantage"
        +        ],
        +        "type": "string"
        +      },
        +      "range": {
        +        "maximum": 9007199254740991,
        +        "minimum": 0,
        +        "type": "integer"
        +      },
        +      "requires": {
        +        "items": {
        +          "additionalProperties": {},
        +          "properties": {
        +            "armorCategories": {
        +              "description": "For 'equipped' + slot:armor: armor category list (Light / Medium / Heavy). OR semantics — match any.",
        +              "items": {
        +                "type": "string"
        +              },
        +              "type": "array"
        +            },
        +            "condition": {
        +              "description": "For 'condition' predicates: the character-state condition to gate on (5e24 named conditions and ongoing-action states).",
        +              "enum": [
        +                "blinded",
        +                "charmed",
        +                "dazed",
        +                "deafened",
        +                "exhaustion",
        +                "frightened",
        +                "grappled",
        +                "incapacitated",
        +                "invisible",
        +                "paralyzed",
        +                "petrified",
        +                "poisoned",
        +                "prone",
        +                "restrained",
        +                "stunned",
        +                "unconscious",
        +                "concentrating",
        +                "grappling",
        +                "dodging",
        +                "hiding",
        +                "raging"
        +              ],
        +              "type": "string"
        +            },
        +            "equipSlot": {
        +              "description": "Body slot the matched weapon must occupy. mainHand / offHand. Resolved via getRequiredSlots so two-handed grips occupy both.",
        +              "enum": [
        +                "mainHand",
        +                "offHand"
        +              ],
        +              "type": "string"
        +            },
        +            "negate": {
        +              "description": "true inverts the predicate — 'while NOT matching' instead of 'while matching'.",
        +              "type": "boolean"
        +            },
        +            "slot": {
        +              "description": "For 'equipped' predicates: the body category to match (armor / shield / weapon).",
        +              "enum": [
        +                "armor",
        +                "shield",
        +                "weapon"
        +              ],
        +              "type": "string"
        +            },
        +            "type": {
        +              "description": "Predicate type. 'equipped' = character-scoped (gates on what's equipped). 'attackingWeapon' = attack-scoped (gates on the current action's source weapon). 'condition' = gates on a character-state condition.",
        +              "enum": [
        +                "equipped",
        +                "attackingWeapon",
        +                "condition"
        +              ],
        +              "type": "string"
        +            },
        +            "weaponProperties": {
        +              "description": "For 'equipped' + slot:weapon OR 'attackingWeapon': weapon-property list. AND semantics — match all.",
        +              "items": {
        +                "type": "string"
        +              },
        +              "type": "array"
        +            }
        +          },
        +          "type": "object"
        +        },
        +        "type": "array"
        +      },
        +      "requiresLogic": {
        +        "enum": [
        +          "and",
        +          "or"
        +        ],
        +        "type": "string"
        +      },
        +      "rollScope": {
        +        "enum": [
        +          "attack",
        +          "save",
        +          "abilityCheck",
        +          "skillCheck"
        +        ],
        +        "type": "string"
        +      },
        +      "trigger": {
        +        "enum": [
        +          "passive",
        +          "toggled",
        +          "reaction",
        +          "perRoll",
        +          "resource",
        +          "targetBound"
        +        ],
        +        "type": "string"
        +      },
        +      "triggerEvent": {
        +        "enum": [
        +          "onHit",
        +          "onMiss",
        +          "onDamage",
        +          "startOfYourTurn",
        +          "endOfYourTurn",
        +          "startOfTargetTurn",
        +          "endOfTargetTurn"
        +        ],
        +        "type": "string"
        +      }
        +    },
        +    "type": "object"
        +  },
        +  "type": "array"
        +}
      • addedInput schema / properties / ruleChoice
        Added value: +{
        +  "additionalProperties": {},
        +  "properties": {
        +    "allowedCategories": {
        +      "items": {
        +        "type": "string"
        +      },
        +      "type": "array"
        +    },
        +    "allowedRuleParameters": {
        +      "additionalProperties": {
        +        "additionalProperties": {},
        +        "properties": {
        +          "damageType": {
        +            "type": "string"
        +          },
        +          "number": {
        +            "maximum": 9007199254740991,
        +            "minimum": 0,
        +            "type": "integer"
        +          },
        +          "range": {
        +            "maximum": 9007199254740991,
        +            "minimum": 0,
        +            "type": "integer"
        +          },
        +          "speed": {
        +            "maximum": 9007199254740991,
        +            "minimum": 0,
        +            "type": "integer"
        +          }
        +        },
        +        "type": "object"
        +      },
        +      "propertyNames": {
        +        "type": "string"
        +      },
        +      "type": "object"
        +    },
        +    "allowedRules": {
        +      "items": {
        +        "description": "Mongo `_id` reference (24-character hex string).",
        +        "minLength": 1,
        +        "type": "string"
        +      },
        +      "type": "array"
        +    },
        +    "allowedTypes": {
        +      "items": {
        +        "type": "string"
        +      },
        +      "type": "array"
        +    },
        +    "count": {
        +      "maximum": 9007199254740991,
        +      "minimum": 0,
        +      "type": "integer"
        +    },
        +    "label": {
        +      "type": "string"
        +    },
        +    "mode": {
        +      "enum": [
        +        "filter",
        +        "specific"
        +      ],
        +      "type": "string"
        +    },
        +    "progression": {
        +      "items": {
        +        "additionalProperties": {},
        +        "properties": {
        +          "count": {
        +            "maximum": 9007199254740991,
        +            "minimum": 0,
        +            "type": "integer"
        +          },
        +          "level": {
        +            "maximum": 20,
        +            "minimum": 1,
        +            "type": "integer"
        +          }
        +        },
        +        "type": "object"
        +      },
        +      "type": "array"
        +    },
        +    "scaling": {
        +      "enum": [
        +        "fixed",
        +        "byLevel"
        +      ],
        +      "type": "string"
        +    }
        +  },
        +  "type": "object"
        +}
      • addedInput schema / properties / ruleset
        Added value: +{
        +  "description": "Ruleset code (e.g. '5th Edition', '5e24', 'PFRPG', 'Savage Worlds').",
        +  "type": "string"
        +}
      • addedInput schema / properties / school
        Added value: +{
        +  "description": "Spell school (Abjuration, Conjuration, Divination, Enchantment, Evocation, Illusion, Necromancy, Transmutation).",
        +  "type": "string"
        +}
      • addedInput schema / properties / source
        Added value: +{
        +  "type": "string"
        +}
      • addedInput schema / properties / spellChoices
        Added value: +{
        +  "items": {
        +    "additionalProperties": {},
        +    "properties": {
        +      "allowedCategories": {
        +        "items": {
        +          "type": "string"
        +        },
        +        "type": "array"
        +      },
        +      "allowedSchools": {
        +        "items": {
        +          "type": "string"
        +        },
        +        "type": "array"
        +      },
        +      "allowedSpells": {
        +        "items": {
        +          "description": "Mongo `_id` reference (24-character hex string).",
        +          "minLength": 1,
        +          "type": "string"
        +        },
        +        "type": "array"
        +      },
        +      "castingAbility": {
        +        "enum": [
        +          "strength",
        +          "dexterity",
        +          "constitution",
        +          "intelligence",
        +          "wisdom",
        +          "charisma"
        +        ],
        +        "type": "string"
        +      },
        +      "castingAbilityOptions": {
        +        "items": {
        +          "enum": [
        +            "strength",
        +            "dexterity",
        +            "constitution",
        +            "intelligence",
        +            "wisdom",
        +            "charisma"
        +          ],
        +          "type": "string"
        +        },
        +        "type": "array"
        +      },
        +      "freeCast": {
        +        "additionalProperties": {},
        +        "properties": {
        +          "atWill": {
        +            "type": "boolean"
        +          },
        +          "count": {
        +            "maximum": 9007199254740991,
        +            "minimum": 0,
        +            "type": "integer"
        +          },
        +          "progression": {
        +            "items": {
        +              "additionalProperties": {},
        +              "properties": {
        +                "count": {
        +                  "maximum": 9007199254740991,
        +                  "minimum": 0,
        +                  "type": "integer"
        +                },
        +                "level": {
        +                  "maximum": 20,
        +                  "minimum": 1,
        +                  "type": "integer"
        +                }
        +              },
        +              "type": "object"
        +            },
        +            "type": "array"
        +          },
        +          "recovery": {
        +            "items": {
        +              "additionalProperties": {},
        +              "properties": {
        +                "count": {
        +                  "maximum": 9007199254740991,
        +                  "minimum": 0,
        +                  "type": "integer"
        +                },
        +                "on": {
        +                  "enum": [
        +                    "Short",
        +                    "Long"
        +                  ],
        +                  "type": "string"
        +                },
        +                "restoreAll": {
        +                  "type": "boolean"
        +                }
        +              },
        +              "type": "object"
        +            },
        +            "type": "array"
        +          }
        +        },
        +        "type": "object"
        +      },
        +      "label": {
        +        "type": "string"
        +      },
        +      "maxLevel": {
        +        "maximum": 9,
        +        "minimum": 0,
        +        "type": "integer"
        +      },
        +      "minLevel": {
        +        "maximum": 9,
        +        "minimum": 0,
        +        "type": "integer"
        +      },
        +      "mode": {
        +        "enum": [
        +          "filter",
        +          "specific"
        +        ],
        +        "type": "string"
        +      },
        +      "prepared": {
        +        "type": "boolean"
        +      },
        +      "progression": {
        +        "items": {
        +          "additionalProperties": {},
        +          "properties": {
        +            "count": {
        +              "maximum": 9007199254740991,
        +              "minimum": 0,
        +              "type": "integer"
        +            },
        +            "level": {
        +              "maximum": 20,
        +              "minimum": 1,
        +              "type": "integer"
        +            }
        +          },
        +          "type": "object"
        +        },
        +        "type": "array"
        +      }
        +    },
        +    "type": "object"
        +  },
        +  "type": "array"
        +}
      • addedInput schema / properties / spellListChoices
        Added value: +{
        +  "items": {
        +    "additionalProperties": {},
        +    "properties": {
        +      "allowedCategories": {
        +        "items": {
        +          "type": "string"
        +        },
        +        "type": "array"
        +      },
        +      "castingAbility": {
        +        "enum": [
        +          "strength",
        +          "dexterity",
        +          "constitution",
        +          "intelligence",
        +          "wisdom",
        +          "charisma"
        +        ],
        +        "type": "string"
        +      },
        +      "castingAbilityOptions": {
        +        "items": {
        +          "enum": [
        +            "strength",
        +            "dexterity",
        +            "constitution",
        +            "intelligence",
        +            "wisdom",
        +            "charisma"
        +          ],
        +          "type": "string"
        +        },
        +        "type": "array"
        +      },
        +      "label": {
        +        "type": "string"
        +      },
        +      "picks": {
        +        "items": {
        +          "additionalProperties": {},
        +          "properties": {
        +            "count": {
        +              "maximum": 9007199254740991,
        +              "minimum": 0,
        +              "type": "integer"
        +            },
        +            "freeCast": {
        +              "additionalProperties": {},
        +              "properties": {
        +                "atWill": {
        +                  "type": "boolean"
        +                },
        +                "count": {
        +                  "maximum": 9007199254740991,
        +                  "minimum": 0,
        +                  "type": "integer"
        +                },
        +                "progression": {
        +                  "items": {
        +                    "additionalProperties": {},
        +                    "properties": {
        +                      "count": {
        +                        "maximum": 9007199254740991,
        +                        "minimum": 0,
        +                        "type": "integer"
        +                      },
        +                      "level": {
        +                        "maximum": 20,
        +                        "minimum": 1,
        +                        "type": "integer"
        +                      }
        +                    },
        +                    "type": "object"
        +                  },
        +                  "type": "array"
        +                },
        +                "recovery": {
        +                  "items": {
        +                    "additionalProperties": {},
        +                    "properties": {
        +                      "count": {
        +                        "maximum": 9007199254740991,
        +                        "minimum": 0,
        +                        "type": "integer"
        +                      },
        +                      "on": {
        +                        "enum": [
        +                          "Short",
        +                          "Long"
        +                        ],
        +                        "type": "string"
        +                      },
        +                      "restoreAll": {
        +                        "type": "boolean"
        +                      }
        +                    },
        +                    "type": "object"
        +                  },
        +                  "type": "array"
        +                }
        +              },
        +              "type": "object"
        +            },
        +            "label": {
        +              "type": "string"
        +            },
        +            "maxLevel": {
        +              "maximum": 9,
        +              "minimum": 0,
        +              "type": "integer"
        +            },
        +            "minLevel": {
        +              "maximum": 9,
        +              "minimum": 0,
        +              "type": "integer"
        +            }
        +          },
        +          "type": "object"
        +        },
        +        "type": "array"
        +      },
        +      "prepared": {
        +        "type": "boolean"
        +      }
        +    },
        +    "type": "object"
        +  },
        +  "type": "array"
        +}
      • addedInput schema / properties / statBonuses
        Added value: +{
        +  "items": {
        +    "additionalProperties": {},
        +    "properties": {
        +      "attribute": {
        +        "description": "For valueType: 'attribute' — which ability's modifier to use.",
        +        "type": "string"
        +      },
        +      "audience": {
        +        "description": "Who the bonus contributes to. Absent = self.",
        +        "enum": [
        +          "self",
        +          "ally",
        +          "any",
        +          "target",
        +          "enemy"
        +        ],
        +        "type": "string"
        +      },
        +      "dice": {
        +        "description": "For valueType: 'dice' — dice expression (e.g. '1d4').",
        +        "type": "string"
        +      },
        +      "durationCount": {
        +        "description": "Numeric count paired with durationUnit (e.g. count: 3, unit: 'round').",
        +        "maximum": 9007199254740991,
        +        "minimum": 0,
        +        "type": "integer"
        +      },
        +      "durationUnit": {
        +        "description": "How long the bonus persists once fired. Only meaningful for event-driven bonuses.",
        +        "enum": [
        +          "instantaneous",
        +          "untilStartOfNextTurn",
        +          "untilEndOfNextTurn",
        +          "round",
        +          "minute",
        +          "hour",
        +          "untilShortRest",
        +          "untilLongRest"
        +        ],
        +        "type": "string"
        +      },
        +      "fixed": {
        +        "description": "For valueType: 'fixed' — the literal numeric contribution.",
        +        "type": "number"
        +      },
        +      "progression": {
        +        "description": "For valueType: 'byLevel' — per-level rows; walker picks the row with level <= current level.",
        +        "items": {
        +          "additionalProperties": {},
        +          "properties": {
        +            "dice": {
        +              "type": "string"
        +            },
        +            "flat": {
        +              "type": "number"
        +            },
        +            "level": {
        +              "maximum": 20,
        +              "minimum": 1,
        +              "type": "integer"
        +            }
        +          },
        +          "type": "object"
        +        },
        +        "type": "array"
        +      },
        +      "range": {
        +        "description": "Aura radius in feet for ally/any-audience bonuses (Aura of Protection's 10 ft.). Absent = no range filter.",
        +        "maximum": 9007199254740991,
        +        "minimum": 0,
        +        "type": "integer"
        +      },
        +      "requires": {
        +        "description": "Optional predicate list that gates this bonus. Absent / empty = always-on.",
        +        "items": {
        +          "additionalProperties": {},
        +          "properties": {
        +            "armorCategories": {
        +              "description": "For 'equipped' + slot:armor: armor category list (Light / Medium / Heavy). OR semantics — match any.",
        +              "items": {
        +                "type": "string"
        +              },
        +              "type": "array"
        +            },
        +            "condition": {
        +              "description": "For 'condition' predicates: the character-state condition to gate on (5e24 named conditions and ongoing-action states).",
        +              "enum": [
        +                "blinded",
        +                "charmed",
        +                "dazed",
        +                "deafened",
        +                "exhaustion",
        +                "frightened",
        +                "grappled",
        +                "incapacitated",
        +                "invisible",
        +                "paralyzed",
        +                "petrified",
        +                "poisoned",
        +                "prone",
        +                "restrained",
        +                "stunned",
        +                "unconscious",
        +                "concentrating",
        +                "grappling",
        +                "dodging",
        +                "hiding",
        +                "raging"
        +              ],
        +              "type": "string"
        +            },
        +            "equipSlot": {
        +              "description": "Body slot the matched weapon must occupy. mainHand / offHand. Resolved via getRequiredSlots so two-handed grips occupy both.",
        +              "enum": [
        +                "mainHand",
        +                "offHand"
        +              ],
        +              "type": "string"
        +            },
        +            "negate": {
        +              "description": "true inverts the predicate — 'while NOT matching' instead of 'while matching'.",
        +              "type": "boolean"
        +            },
        +            "slot": {
        +              "description": "For 'equipped' predicates: the body category to match (armor / shield / weapon).",
        +              "enum": [
        +                "armor",
        +                "shield",
        +                "weapon"
        +              ],
        +              "type": "string"
        +            },
        +            "type": {
        +              "description": "Predicate type. 'equipped' = character-scoped (gates on what's equipped). 'attackingWeapon' = attack-scoped (gates on the current action's source weapon). 'condition' = gates on a character-state condition.",
        +              "enum": [
        +                "equipped",
        +                "attackingWeapon",
        +                "condition"
        +              ],
        +              "type": "string"
        +            },
        +            "weaponProperties": {
        +              "description": "For 'equipped' + slot:weapon OR 'attackingWeapon': weapon-property list. AND semantics — match all.",
        +              "items": {
        +                "type": "string"
        +              },
        +              "type": "array"
        +            }
        +          },
        +          "type": "object"
        +        },
        +        "type": "array"
        +      },
        +      "requiresLogic": {
        +        "description": "How `requires` predicates compose. 'and' (default) = ALL must hold. 'or' = ANY one is sufficient.",
        +        "enum": [
        +          "and",
        +          "or"
        +        ],
        +        "type": "string"
        +      },
        +      "target": {
        +        "description": "Stat the bonus contributes to (e.g. 'skills.Acrobatics.misc', 'attributes.strength.misc').",
        +        "type": "string"
        +      },
        +      "trigger": {
        +        "description": "Action-economy / cost shape of the bonus. passive / toggled / reaction / perRoll / resource / targetBound.",
        +        "enum": [
        +          "passive",
        +          "toggled",
        +          "reaction",
        +          "perRoll",
        +          "resource",
        +          "targetBound"
        +        ],
        +        "type": "string"
        +      },
        +      "triggerEvent": {
        +        "description": "Game-time event that fires the bonus (onHit / onDamage / startOfYourTurn / etc.). Absent = not event-driven (passive walker contributes whenever `requires` holds).",
        +        "enum": [
        +          "onHit",
        +          "onMiss",
        +          "onDamage",
        +          "startOfYourTurn",
        +          "endOfYourTurn",
        +          "startOfTargetTurn",
        +          "endOfTargetTurn"
        +        ],
        +        "type": "string"
        +      },
        +      "types": {
        +        "description": "Damage type tags for damage.* targets. No-op for non-damage targets.",
        +        "items": {
        +          "type": "string"
        +        },
        +        "type": "array"
        +      },
        +      "valueType": {
        +        "description": "How the contribution is computed. 'fixed' uses `fixed`; 'attribute' uses the mod of `attribute`; 'attackAttribute' uses the action's attack-roll ability (per-attack only); others scale by level/PB/dice.",
        +        "enum": [
        +          "fixed",
        +          "attribute",
        +          "proficiency",
        +          "level",
        +          "halfLevel",
        +          "dice",
        +          "byLevel",
        +          "attackAttribute"
        +        ],
        +        "type": "string"
        +      }
        +    },
        +    "type": "object"
        +  },
        +  "type": "array"
        +}
      • addedInput schema / properties / summary
        Added value: +{
        +  "description": "Short one-line summary.",
        +  "type": "string"
        +}
      • addedInput schema / properties / type
        Added value: +{
        +  "description": "Spell type. 5e / 5e24 use 'Spell'; Savage Worlds uses 'Power'. Required at create.",
        +  "enum": [
        +    "Spell",
        +    "Power"
        +  ],
        +  "type": "string"
        +}
      • addedInput schema / properties / uses
        Added value: +{
        +  "items": {
        +    "additionalProperties": {},
        +    "properties": {
        +      "count": {
        +        "maximum": 9007199254740991,
        +        "minimum": 0,
        +        "type": "integer"
        +      },
        +      "mode": {
        +        "enum": [
        +          "fixed",
        +          "byLevel",
        +          "proficiency"
        +        ],
        +        "type": "string"
        +      },
        +      "name": {
        +        "type": "string"
        +      },
        +      "progression": {
        +        "items": {
        +          "additionalProperties": {},
        +          "properties": {
        +            "count": {
        +              "maximum": 9007199254740991,
        +              "minimum": 0,
        +              "type": "integer"
        +            },
        +            "countAbility": {
        +              "enum": [
        +                "strength",
        +                "dexterity",
        +                "constitution",
        +                "intelligence",
        +                "wisdom",
        +                "charisma"
        +              ],
        +              "type": "string"
        +            },
        +            "countSource": {
        +              "enum": [
        +                "fixed",
        +                "proficiency",
        +                "abilityMod"
        +              ],
        +              "type": "string"
        +            },
        +            "level": {
        +              "maximum": 20,
        +              "minimum": 1,
        +              "type": "integer"
        +            },
        +            "slotLevel": {
        +              "maximum": 9,
        +              "minimum": 1,
        +              "type": "integer"
        +            }
        +          },
        +          "type": "object"
        +        },
        +        "type": "array"
        +      },
        +      "recovery": {
        +        "items": {
        +          "additionalProperties": {},
        +          "properties": {
        +            "count": {
        +              "maximum": 9007199254740991,
        +              "minimum": 0,
        +              "type": "integer"
        +            },
        +            "on": {
        +              "enum": [
        +                "Short",
        +                "Long"
        +              ],
        +              "type": "string"
        +            },
        +            "restoreAll": {
        +              "type": "boolean"
        +            }
        +          },
        +          "type": "object"
        +        },
        +        "type": "array"
        +      },
        +      "rest": {
        +        "enum": [
        +          "Short",
        +          "Long"
        +        ],
        +        "type": "string"
        +      },
        +      "slotLevel": {
        +        "maximum": 9,
        +        "minimum": 1,
        +        "type": "integer"
        +      }
        +    },
        +    "type": "object"
        +  },
        +  "type": "array"
        +}
      • addedInput schema / required
        Added value: +[
        +  "name"
        +]
    • Changedvault_level_up_pc17 fields changed
      • addedInput schema / $schema
        Added value: +"http://json-schema.org/draft-07/schema#"
      • addedInput schema / additionalProperties
        Added value: +{}
      • addedInput schema / properties / abilityBumpPicks
        Added value: +{
        +  "additionalProperties": {
        +    "additionalProperties": {},
        +    "properties": {
        +      "lines": {
        +        "items": {
        +          "items": {
        +            "type": "string"
        +          },
        +          "type": "array"
        +        },
        +        "type": "array"
        +      },
        +      "option": {
        +        "maximum": 9007199254740991,
        +        "minimum": 0,
        +        "type": "integer"
        +      }
        +    },
        +    "type": "object"
        +  },
        +  "description": "Ability-score-increase picks for a gained rule carrying an `abilityScoreBump` (the ASI feat picked at level 4+): `{ option, lines }` keyed by the granting rule's `_id`, same shape as `vault_build_pc`. A Constitution increase raises HP retroactively for every level already held.",
        +  "propertyNames": {
        +    "type": "string"
        +  },
        +  "type": "object"
        +}
      • addedInput schema / properties / abilityChoices
        Added value: +{
        +  "additionalProperties": {
        +    "items": {
        +      "type": "string"
        +    },
        +    "type": "array"
        +  },
        +  "description": "ruleChoice picks, keyed by the OWNING rule's `_id`: a gained feature's choice (a Fighting Style; the class's subclass-choice ability at level 3 — value = the picked subclass `_id`; an ASI ability — value = the picked feat `_id`) AND a grown held rule's choice (`growth[]` entries, e.g. new invocations — supply the NEW picks only, the delta count). A picked option's own sub-choices (a feat's skill picks, its abilityScoreBump) go in the other maps keyed by the picked option's `_id`, exactly as in `vault_build_pc`. Pools are prerequisite-filtered; an unqualified pick rejects the draft.",
        +  "propertyNames": {
        +    "type": "string"
        +  },
        +  "type": "object"
        +}
      • addedInput schema / properties / allowIncomplete
        Added value: +{
        +  "description": "Sanctioned partial apply: `true` lets vault accept UNDER-filled pick families — the level lands and only what was picked is granted; the shortfall is simply skipped (the player can edit the sheet later). Overfilled, duplicate, out-of-pool, and prerequisite-failing picks still reject. Use it as the escape when a surfaced pick cannot be satisfied; never as a shortcut past picks you can supply.",
        +  "type": "boolean"
        +}
      • addedInput schema / properties / castingAbilityPicks
        Added value: +{
        +  "additionalProperties": {
        +    "enum": [
        +      "strength",
        +      "dexterity",
        +      "constitution",
        +      "intelligence",
        +      "wisdom",
        +      "charisma"
        +    ],
        +    "type": "string"
        +  },
        +  "description": "Spellcasting-ability picks for blocks surfacing `castingAbilityOptions`, keyed like spellChoicePicks.",
        +  "propertyNames": {
        +    "type": "string"
        +  },
        +  "type": "object"
        +}
      • addedInput schema / properties / characterId
        Added value: +{
        +  "description": "`_id` of the character to level (must belong to the calling user).",
        +  "minLength": 1,
        +  "type": "string"
        +}
      • addedInput schema / properties / classRuleId
        Added value: +{
        +  "description": "Required. The base Class rule to advance one level — a held class entry (its stored level bumps) or a class the character doesn't hold yet (multiclass: a second class entry is stamped at level 1). From the chooser's `classEntries[].classRuleId` / `multiclassOptions[]._id`.",
        +  "minLength": 1,
        +  "type": "string"
        +}
      • addedInput schema / properties / hitPoints
        Added value: +{
        +  "additionalProperties": {},
        +  "description": "How the level's hit points are gained: `{method:'average'}` takes the fixed average (the plan's `hitPoints.average`); `{method:'roll', value}` records a die the PLAYER rolled — value must be 1..the class's hit die. The Constitution modifier is added server-side either way.",
        +  "properties": {
        +    "method": {
        +      "enum": [
        +        "average",
        +        "roll"
        +      ],
        +      "type": "string"
        +    },
        +    "value": {
        +      "exclusiveMinimum": 0,
        +      "maximum": 9007199254740991,
        +      "type": "integer"
        +    }
        +  },
        +  "required": [
        +    "method"
        +  ],
        +  "type": "object"
        +}
      • addedInput schema / properties / multiclassSkillProficiencies
        Added value: +{
        +  "description": "Skill picks for the entered class's `multiclassGrants.skillChoices` (multiclass only): exactly `count` names from its options.",
        +  "items": {
        +    "type": "string"
        +  },
        +  "type": "array"
        +}
      • addedInput schema / properties / multiclassToolProficiencies
        Added value: +{
        +  "description": "Tool picks for the entered class's `multiclassGrants.toolChoices` (multiclass only): exactly `count` names from its (group-expanded) options.",
        +  "items": {
        +    "type": "string"
        +  },
        +  "type": "array"
        +}
      • addedInput schema / properties / preparedSpellPicks
        Added value: +{
        +  "additionalProperties": {
        +    "items": {
        +      "description": "Mongo `_id` reference (24-character hex string).",
        +      "minLength": 1,
        +      "type": "string"
        +    },
        +    "type": "array"
        +  },
        +  "description": "\"Prepare N more\" picks for rules whose preparedSpells count grew, keyed by the granting rule's `_id`. The pool is the character's UNPREPARED granted leveled spells plus any picked this level-up; send exactly the plan's surfaced count.",
        +  "propertyNames": {
        +    "type": "string"
        +  },
        +  "type": "object"
        +}
      • addedInput schema / properties / proficiencyChoicePicks
        Added value: +{
        +  "additionalProperties": {
        +    "items": {
        +      "type": "string"
        +    },
        +    "type": "array"
        +  },
        +  "description": "Picks for proficiencyChoices grants on gained/grown rules, keyed `\"<ruleId>:<grantIndex>\"` — same keying and rules as `vault_build_pc`. Grown grants demand only the DELTA count the plan surfaced. An EXPERTISE grant's pool is the character's proficient skills MINUS those that already carry Expertise (narrowed to the grant's own options for mode 'specific'); when that pool is at/below the count, vault auto-grants and expects NO picks.",
        +  "propertyNames": {
        +    "type": "string"
        +  },
        +  "type": "object"
        +}
      • addedInput schema / properties / spellChoicePicks
        Added value: +{
        +  "additionalProperties": {
        +    "items": {
        +      "description": "Mongo `_id` reference (24-character hex string).",
        +      "minLength": 1,
        +      "type": "string"
        +    },
        +    "type": "array"
        +  },
        +  "description": "Picks for spellChoices blocks on gained/grown rules, keyed `\"<ruleId>:<blockIndex>\"` (authored index — the projected array may hold nulls; count them). Grown blocks demand only the DELTA count (\"learn N more spells\").",
        +  "propertyNames": {
        +    "type": "string"
        +  },
        +  "type": "object"
        +}
      • addedInput schema / properties / spellListChoicePicks
        Added value: +{
        +  "additionalProperties": {
        +    "additionalProperties": {},
        +    "properties": {
        +      "castingAbility": {
        +        "enum": [
        +          "strength",
        +          "dexterity",
        +          "constitution",
        +          "intelligence",
        +          "wisdom",
        +          "charisma"
        +        ],
        +        "type": "string"
        +      },
        +      "category": {
        +        "type": "string"
        +      },
        +      "picks": {
        +        "additionalProperties": {
        +          "items": {
        +            "description": "Mongo `_id` reference (24-character hex string).",
        +            "minLength": 1,
        +            "type": "string"
        +          },
        +          "type": "array"
        +        },
        +        "propertyNames": {
        +          "type": "string"
        +        },
        +        "type": "object"
        +      }
        +    },
        +    "type": "object"
        +  },
        +  "description": "Picks for a NEWLY gained rule's spellListChoices (the Magic Initiate shape) — `{ category, picks, castingAbility? }` keyed `\"<ruleId>:<blockIndex>\"`, exactly as in `vault_build_pc`.",
        +  "propertyNames": {
        +    "type": "string"
        +  },
        +  "type": "object"
        +}
      • addedInput schema / properties / xp
        Added value: +{
        +  "description": "The character's total XP after this level-up, for tables tracking exact XP. Must be >= the plan's `xp.minimumForNewTotal`; omit to let vault floor the stored XP at that minimum.",
        +  "maximum": 9007199254740991,
        +  "minimum": 0,
        +  "type": "integer"
        +}
      • addedInput schema / required
        Added value: +[
        +  "characterId",
        +  "classRuleId",
        +  "hitPoints"
        +]
    • Changedvault_record_pc_classes5 fields changed
      • addedInput schema / $schema
        Added value: +"http://json-schema.org/draft-07/schema#"
      • addedInput schema / additionalProperties
        Added value: +{}
      • addedInput schema / properties / characterId
        Added value: +{
        +  "description": "`_id` of the class-less character (must belong to the calling user).",
        +  "minLength": 1,
        +  "type": "string"
        +}
      • addedInput schema / properties / classes
        Added value: +{
        +  "description": "One row per class the character already has, distinct classes only. The levels MUST sum to exactly the RECORD-mode chooser's `totalLevel` (the character's XP-derived level) — vault rejects any other split and never rewrites XP.",
        +  "items": {
        +    "additionalProperties": {},
        +    "properties": {
        +      "classRuleId": {
        +        "description": "A base Class rule `_id` from the RECORD-mode chooser's `recordOptions[]._id`.",
        +        "minLength": 1,
        +        "type": "string"
        +      },
        +      "level": {
        +        "description": "The level the character already has in this class.",
        +        "maximum": 20,
        +        "minimum": 1,
        +        "type": "integer"
        +      },
        +      "subclassRuleId": {
        +        "description": "Optional: the subclass already picked, from the option's `subclasses[]._id`. Valid only when this row's level has reached the option's `subclassLevel` (a class picks its subclass at that level; null = no gate).",
        +        "minLength": 1,
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "classRuleId",
        +      "level"
        +    ],
        +    "type": "object"
        +  },
        +  "minItems": 1,
        +  "type": "array"
        +}
      • addedInput schema / required
        Added value: +[
        +  "characterId",
        +  "classes"
        +]
    • Changedvault_update_character28 fields changed
      • addedInput schema / $schema
        Added value: +"http://json-schema.org/draft-07/schema#"
      • addedInput schema / additionalProperties
        Added value: +{}
      • addedInput schema / properties / actions
        Added value: +{
        +  "items": {
        +    "additionalProperties": {},
        +    "properties": {
        +      "_item": {
        +        "description": "Optional back-reference to the Vault Item this action was built from.",
        +        "minLength": 1,
        +        "type": "string"
        +      },
        +      "_rule": {
        +        "description": "Optional back-reference to the Vault Rule this action was built from.",
        +        "minLength": 1,
        +        "type": "string"
        +      },
        +      "_spell": {
        +        "description": "Optional back-reference to the Vault Spell this action was built from.",
        +        "minLength": 1,
        +        "type": "string"
        +      },
        +      "actions": {
        +        "description": "PF Playtest action-economy marker (F/1/2/3/R).",
        +        "type": "string"
        +      },
        +      "attack": {
        +        "additionalProperties": {},
        +        "properties": {
        +          "attribute": {
        +            "description": "Ability driving the to-hit roll (e.g. 'strength', 'charisma' for spell attacks).",
        +            "type": "string"
        +          },
        +          "magic": {
        +            "type": "number"
        +          },
        +          "misc": {
        +            "type": "number"
        +          },
        +          "proficiency": {
        +            "type": "number"
        +          },
        +          "skill": {
        +            "type": "string"
        +          }
        +        },
        +        "type": "object"
        +      },
        +      "damage": {
        +        "additionalProperties": {},
        +        "properties": {
        +          "attribute": {
        +            "description": "Ability whose modifier is added to damage.",
        +            "type": "string"
        +          },
        +          "critical": {
        +            "type": "string"
        +          },
        +          "dice": {
        +            "description": "Base damage dice expression (e.g. '2d8'). Additional damage types live in `description` per Rule 11.",
        +            "type": "string"
        +          },
        +          "magic": {
        +            "type": "number"
        +          },
        +          "misc": {
        +            "type": "number"
        +          },
        +          "type": {
        +            "description": "Damage type ('piercing', 'fire', etc.). Source-exact, capitalize if the source does.",
        +            "type": "string"
        +          }
        +        },
        +        "type": "object"
        +      },
        +      "description": {
        +        "type": "string"
        +      },
        +      "name": {
        +        "type": "string"
        +      },
        +      "proficient": {
        +        "type": "boolean"
        +      },
        +      "range": {
        +        "type": "string"
        +      },
        +      "rof": {
        +        "description": "Savage Worlds Rate of Fire.",
        +        "type": "number"
        +      },
        +      "summary": {
        +        "type": "string"
        +      },
        +      "type": {
        +        "description": "Action type. 5e24 uses 'Melee' / 'Range' / 'Special' / 'Reaction' / 'Legendary' / 'Bonus'.",
        +        "type": "string"
        +      }
        +    },
        +    "type": "object"
        +  },
        +  "type": "array"
        +}
      • addedInput schema / properties / active
        Added value: +{
        +  "type": "boolean"
        +}
      • addedInput schema / properties / aspects
        Added value: +{
        +  "items": {
        +    "additionalProperties": {},
        +    "properties": {
        +      "description": {
        +        "type": "string"
        +      },
        +      "kind": {
        +        "description": "One of 'high concept', 'trouble', 'character', 'consequence'.",
        +        "type": "string"
        +      },
        +      "name": {
        +        "description": "The aspect's phrase. A consequence slot carries its cost while blank.",
        +        "type": "string"
        +      },
        +      "shifts": {
        +        "description": "Consequence/condition slots only: harm absorbed. Fate: 2 Mild, 4 Moderate, 6 Severe, 8 Extreme (Fate Accelerated omits Extreme). Demon Hunters conditions: 5 Mild, 10 Moderate, 15 Severe.",
        +        "type": "number"
        +      }
        +    },
        +    "type": "object"
        +  },
        +  "type": "array"
        +}
      • addedInput schema / properties / attributes
        Added value: +{
        +  "items": {
        +    "additionalProperties": {},
        +    "properties": {
        +      "misc": {
        +        "description": "Misc bonus on the save (5e/5e24). Used for high-PB monster compensation.",
        +        "type": "number"
        +      },
        +      "name": {
        +        "description": "Ability name: strength / dexterity / constitution / intelligence / wisdom / charisma. Lowercase.",
        +        "type": "string"
        +      },
        +      "proficient": {
        +        "description": "Save proficiency flag (5e/5e24). When true, PB is added to the save.",
        +        "type": "boolean"
        +      },
        +      "score": {
        +        "description": "Raw ability score (e.g. 17). Modifier is derived by the sheet.",
        +        "type": "number"
        +      },
        +      "temp": {
        +        "type": "number"
        +      }
        +    },
        +    "type": "object"
        +  },
        +  "type": "array"
        +}
      • addedInput schema / properties / baseUpdatedAt
        Added value: +{
        +  "description": "REQUIRED proof that you are working from the latest version: copy the `updatedAt` value verbatim from a FRESH read of this exact record (use the matching get tool first). Values from memory, from an earlier conversation, or guessed timestamps are rejected with OUT_OF_SYNC and nothing is written. After a successful update, the response carries the new `updatedAt` — use that for any follow-up write.",
        +  "minLength": 1,
        +  "type": "string"
        +}
      • addedInput schema / properties / core
        Added value: +{
        +  "additionalProperties": {},
        +  "properties": {
        +    "age": {
        +      "type": "string"
        +    },
        +    "alignment": {
        +      "type": "string"
        +    },
        +    "ancestry": {
        +      "type": "string"
        +    },
        +    "background": {
        +      "type": "string"
        +    },
        +    "baseAttackBonus": {
        +      "type": "number"
        +    },
        +    "charisma": {
        +      "type": "string"
        +    },
        +    "class": {
        +      "description": "Character class as free-form text. PCs use a Class rule via rules[]; this field is the display string.",
        +      "type": "string"
        +    },
        +    "cr": {
        +      "type": "string"
        +    },
        +    "deity": {
        +      "type": "string"
        +    },
        +    "experience": {
        +      "description": "Character-level XP (no commas). For monsters, the value from the CR→level XP table.",
        +      "type": "string"
        +    },
        +    "eyes": {
        +      "type": "string"
        +    },
        +    "gender": {
        +      "type": "string"
        +    },
        +    "hair": {
        +      "type": "string"
        +    },
        +    "height": {
        +      "type": "string"
        +    },
        +    "homeland": {
        +      "type": "string"
        +    },
        +    "languages": {
        +      "type": "string"
        +    },
        +    "proficiencies": {
        +      "type": "string"
        +    },
        +    "pronouns": {
        +      "description": "The character's pronouns as free-form text (e.g. 'she/her', 'they/them').",
        +      "type": "string"
        +    },
        +    "race": {
        +      "description": "Creature type for monsters (e.g. 'Elemental', 'Humanoid', 'Dragon (Chromatic)'); race for PCs.",
        +      "type": "string"
        +    },
        +    "refresh": {
        +      "description": "Session-start resource: fate points (Fate — Refresh) or faith dice (Demon Hunters — Devotion). The total the character resets to at the start of a session.",
        +      "type": "number"
        +    },
        +    "size": {
        +      "description": "Creature size. Exact source text including 'or' for variable sizes ('Medium or Small').",
        +      "type": "string"
        +    },
        +    "skin": {
        +      "type": "string"
        +    },
        +    "spellCastingAttribute": {
        +      "type": "string"
        +    },
        +    "weight": {
        +      "type": "string"
        +    }
        +  },
        +  "type": "object"
        +}
      • addedInput schema / properties / dead
        Added value: +{
        +  "type": "boolean"
        +}
      • addedInput schema / properties / defense
        Added value: +{
        +  "additionalProperties": {},
        +  "properties": {
        +    "armorClass": {
        +      "additionalProperties": {},
        +      "description": "Layered AC rows the sheet sums. IMPORTANT (5e24): when the character's `settings.autoPassiveBonuses` is true — the default for new 5e24 characters — the `armor` and `shield` rows are DERIVED from equipped items and recomputed on every sheet load, so writing them here gets overwritten. Change AC by setting `equipped: true/false` on the character's armor/shield items instead. When the toggle is false (and on all other rulesets), these rows are manually authored and writing them here is correct. `magic` and `misc` are manual in both modes. Check the toggle with vault_get_character before writing.",
        +      "properties": {
        +        "armor": {
        +          "additionalProperties": {},
        +          "properties": {
        +            "bonus": {
        +              "description": "Base AC value the sheet adds DEX to. See the 5e24 monster guide Rule 1 for the math.",
        +              "type": "number"
        +            },
        +            "checkPenalty": {
        +              "type": "number"
        +            },
        +            "description": {
        +              "description": "Armor name ('Natural Armor', 'Chain Shirt') or null when AC derives from DEX only.",
        +              "type": "string"
        +            },
        +            "heavy": {
        +              "description": "True suppresses DEX contribution entirely (heavy armor).",
        +              "type": "boolean"
        +            },
        +            "maxDex": {
        +              "type": "number"
        +            },
        +            "medium": {
        +              "description": "True caps DEX contribution to +2 (medium armor).",
        +              "type": "boolean"
        +            },
        +            "proficiency": {
        +              "type": "number"
        +            },
        +            "speed": {
        +              "type": "string"
        +            },
        +            "speedPenalty": {
        +              "type": "string"
        +            },
        +            "spellFail": {
        +              "type": "string"
        +            },
        +            "touchBonus": {
        +              "type": "number"
        +            }
        +          },
        +          "type": "object"
        +        },
        +        "arms": {
        +          "additionalProperties": {},
        +          "properties": {
        +            "bonus": {
        +              "type": "number"
        +            },
        +            "description": {
        +              "type": "string"
        +            }
        +          },
        +          "type": "object"
        +        },
        +        "deflection": {
        +          "additionalProperties": {},
        +          "properties": {
        +            "bonus": {
        +              "type": "number"
        +            },
        +            "description": {
        +              "type": "string"
        +            }
        +          },
        +          "type": "object"
        +        },
        +        "dodge": {
        +          "additionalProperties": {},
        +          "properties": {
        +            "bonus": {
        +              "type": "number"
        +            },
        +            "description": {
        +              "type": "string"
        +            }
        +          },
        +          "type": "object"
        +        },
        +        "head": {
        +          "additionalProperties": {},
        +          "properties": {
        +            "bonus": {
        +              "type": "number"
        +            },
        +            "description": {
        +              "type": "string"
        +            }
        +          },
        +          "type": "object"
        +        },
        +        "legs": {
        +          "additionalProperties": {},
        +          "properties": {
        +            "bonus": {
        +              "type": "number"
        +            },
        +            "description": {
        +              "type": "string"
        +            }
        +          },
        +          "type": "object"
        +        },
        +        "magic": {
        +          "additionalProperties": {},
        +          "properties": {
        +            "bonus": {
        +              "type": "number"
        +            },
        +            "description": {
        +              "type": "string"
        +            }
        +          },
        +          "type": "object"
        +        },
        +        "misc": {
        +          "additionalProperties": {},
        +          "properties": {
        +            "bonus": {
        +              "type": "number"
        +            },
        +            "description": {
        +              "type": "string"
        +            }
        +          },
        +          "type": "object"
        +        },
        +        "natural": {
        +          "additionalProperties": {},
        +          "properties": {
        +            "bonus": {
        +              "type": "number"
        +            },
        +            "description": {
        +              "type": "string"
        +            }
        +          },
        +          "type": "object"
        +        },
        +        "shield": {
        +          "additionalProperties": {},
        +          "properties": {
        +            "bonus": {
        +              "type": "number"
        +            },
        +            "checkPenalty": {
        +              "type": "number"
        +            },
        +            "description": {
        +              "type": "string"
        +            },
        +            "maxDex": {
        +              "type": "number"
        +            },
        +            "proficiency": {
        +              "type": "number"
        +            },
        +            "raised": {
        +              "type": "boolean"
        +            },
        +            "spellFail": {
        +              "type": "number"
        +            },
        +            "touchBonus": {
        +              "type": "number"
        +            }
        +          },
        +          "type": "object"
        +        }
        +      },
        +      "type": "object"
        +    },
        +    "damageReduction": {
        +      "type": "string"
        +    },
        +    "deathSaves": {
        +      "additionalProperties": {},
        +      "properties": {
        +        "failures": {
        +          "items": {
        +            "type": "string"
        +          },
        +          "type": "array"
        +        },
        +        "successes": {
        +          "items": {
        +            "type": "string"
        +          },
        +          "type": "array"
        +        }
        +      },
        +      "type": "object"
        +    },
        +    "dying": {
        +      "additionalProperties": {},
        +      "properties": {
        +        "current": {
        +          "type": "number"
        +        },
        +        "wounds": {
        +          "type": "number"
        +        }
        +      },
        +      "type": "object"
        +    },
        +    "exhaustion": {
        +      "description": "5e24 Exhaustion level (0-6). Absent = 0 (not exhausted). Each level is -2 to d20 Tests and -5 ft Speed; level 6 = death. A Long Rest via the vault rest control reduces it by 1.",
        +      "maximum": 6,
        +      "minimum": 0,
        +      "type": "integer"
        +    },
        +    "health": {
        +      "additionalProperties": {},
        +      "properties": {
        +        "fatigue": {
        +          "type": "number"
        +        },
        +        "incapacitated": {
        +          "type": "boolean"
        +        },
        +        "wounds": {
        +          "type": "number"
        +        }
        +      },
        +      "type": "object"
        +    },
        +    "hitDice": {
        +      "additionalProperties": {},
        +      "properties": {
        +        "current": {
        +          "description": "Unspent hit dice count. When `pools` is present (5e24 class characters), this is the derived sum of pool currents — keep it consistent with pools on write.",
        +          "type": "number"
        +        },
        +        "dice": {
        +          "description": "Without `pools` (monsters, non-5e24): per-die expression, NOT the multiplied total — size-mapped Tiny d4 / Small d6 / Medium d8 / Large d10 / Huge d12 / Gargantuan d20, see monster guide Rule 20. When `pools` is present (5e24 class characters): the derived compound string ('5d10 + 5d6') — keep it consistent with pools on write.",
        +          "type": "string"
        +        },
        +        "pools": {
        +          "description": "5e24 per-die-size Hit Dice pools — the AUTHORITATIVE representation (one entry per die size a multiclass character has). Maintained by creation, level-up, and a one-shot backfill; player edits win. The server does NOT re-derive the legacy fields on write, so when writing hit dice for a character with pools, write pools AND the legacy current/dice consistently (current = sum of pool currents; dice = compound string).",
        +          "items": {
        +            "additionalProperties": {},
        +            "properties": {
        +              "current": {
        +                "maximum": 9007199254740991,
        +                "minimum": 0,
        +                "type": "integer"
        +              },
        +              "dice": {
        +                "description": "Die size of this pool, e.g. 'd10'.",
        +                "type": "string"
        +              },
        +              "maximum": {
        +                "maximum": 9007199254740991,
        +                "minimum": 0,
        +                "type": "integer"
        +              }
        +            },
        +            "type": "object"
        +          },
        +          "type": "array"
        +        }
        +      },
        +      "type": "object"
        +    },
        +    "hitPoints": {
        +      "additionalProperties": {},
        +      "properties": {
        +        "current": {
        +          "type": "number"
        +        },
        +        "maximum": {
        +          "type": "number"
        +        },
        +        "temp": {
        +          "type": "number"
        +        }
        +      },
        +      "type": "object"
        +    },
        +    "parryBonus": {
        +      "type": "number"
        +    },
        +    "savingThrows": {
        +      "items": {
        +        "additionalProperties": {},
        +        "properties": {
        +          "attribute": {
        +            "type": "string"
        +          },
        +          "base": {
        +            "type": "number"
        +          },
        +          "magic": {
        +            "type": "number"
        +          },
        +          "misc": {
        +            "type": "number"
        +          },
        +          "name": {
        +            "type": "string"
        +          },
        +          "proficiency": {
        +            "type": "number"
        +          },
        +          "temp": {
        +            "type": "number"
        +          }
        +        },
        +        "type": "object"
        +      },
        +      "type": "array"
        +    },
        +    "spellResistance": {
        +      "type": "string"
        +    },
        +    "toughnessBonus": {
        +      "type": "number"
        +    }
        +  },
        +  "type": "object"
        +}
      • addedInput schema / properties / description
        Added value: +{
        +  "type": "string"
        +}
      • addedInput schema / properties / id
        Added value: +{
        +  "description": "Mongo `_id` of the character to update.",
        +  "minLength": 1,
        +  "type": "string"
        +}
      • addedInput schema / properties / image
        Added value: +{
        +  "additionalProperties": {},
        +  "properties": {
        +    "url": {
        +      "description": "Image URL hosted on Embers Images (or any addressable HTTPS URL).",
        +      "type": "string"
        +    }
        +  },
        +  "type": "object"
        +}
      • addedInput schema / properties / items
        Added value: +{
        +  "items": {
        +    "additionalProperties": {},
        +    "properties": {
        +      "_ref": {
        +        "description": "Mongo `_id` reference (24-character hex string).",
        +        "minLength": 1,
        +        "type": "string"
        +      },
        +      "armorCategory": {
        +        "type": "string"
        +      },
        +      "armorClass": {
        +        "type": "number"
        +      },
        +      "carried": {
        +        "type": "boolean"
        +      },
        +      "cost": {
        +        "type": "number"
        +      },
        +      "damageDice": {
        +        "type": "string"
        +      },
        +      "damageType": {
        +        "items": {
        +          "type": "string"
        +        },
        +        "type": "array"
        +      },
        +      "description": {
        +        "type": "string"
        +      },
        +      "detail": {
        +        "type": "string"
        +      },
        +      "equipSlot": {
        +        "type": "string"
        +      },
        +      "equipSlots": {
        +        "items": {
        +          "type": "string"
        +        },
        +        "type": "array"
        +      },
        +      "equipped": {
        +        "description": "Monsters: ALWAYS false. Never set equipped/equipSlot on a monster's items.",
        +        "type": "boolean"
        +      },
        +      "image": {
        +        "additionalProperties": {},
        +        "properties": {
        +          "url": {
        +            "description": "Image URL hosted on Embers Images (or any addressable HTTPS URL).",
        +            "type": "string"
        +          }
        +        },
        +        "type": "object"
        +      },
        +      "mastery": {
        +        "type": "string"
        +      },
        +      "maxDexModifier": {
        +        "type": "number"
        +      },
        +      "name": {
        +        "type": "string"
        +      },
        +      "properties": {
        +        "items": {
        +          "additionalProperties": {},
        +          "properties": {
        +            "ammoType": {
        +              "type": "string"
        +            },
        +            "damage": {
        +              "type": "string"
        +            },
        +            "display": {
        +              "type": "string"
        +            },
        +            "name": {
        +              "type": "string"
        +            },
        +            "range": {
        +              "additionalProperties": {},
        +              "properties": {
        +                "long": {
        +                  "type": "number"
        +                },
        +                "normal": {
        +                  "type": "number"
        +                }
        +              },
        +              "type": "object"
        +            }
        +          },
        +          "type": "object"
        +        },
        +        "type": "array"
        +      },
        +      "quantity": {
        +        "type": "number"
        +      },
        +      "sourceSpell": {
        +        "description": "Auto-managed. Link to the spell that manufactured this companion armor item (e.g. Mage Armor, which the vault sheet offers as an equippable Light armor). The sheet sets and maintains it; if it's present on an item you're editing, preserve it verbatim, and never set, change, or invent it. Dropping it on a round-trip de-links the companion and leaves a duplicate item on the sheet.",
        +        "minLength": 1,
        +        "type": "string"
        +      },
        +      "stealthDisadvantage": {
        +        "type": "boolean"
        +      },
        +      "stock": {
        +        "type": "boolean"
        +      },
        +      "strengthRequirement": {
        +        "type": "number"
        +      },
        +      "summary": {
        +        "type": "string"
        +      },
        +      "twoHandedGrip": {
        +        "type": "boolean"
        +      },
        +      "type": {
        +        "type": "string"
        +      },
        +      "weaponType": {
        +        "type": "string"
        +      },
        +      "weight": {
        +        "type": "number"
        +      }
        +    },
        +    "type": "object"
        +  },
        +  "type": "array"
        +}
      • addedInput schema / properties / name
        Added value: +{
        +  "description": "Character display name.",
        +  "minLength": 1,
        +  "type": "string"
        +}
      • addedInput schema / properties / notes
        Added value: +{
        +  "items": {
        +    "additionalProperties": {},
        +    "properties": {
        +      "description": {
        +        "description": "Note body. Free-form markdown.",
        +        "type": "string"
        +      },
        +      "name": {
        +        "description": "Note title. Used as the visible heading on the character sheet.",
        +        "type": "string"
        +      }
        +    },
        +    "type": "object"
        +  },
        +  "type": "array"
        +}
      • addedInput schema / properties / offense
        Added value: +{
        +  "additionalProperties": {},
        +  "properties": {
        +    "initiative": {
        +      "additionalProperties": {},
        +      "properties": {
        +        "attribute": {
        +          "description": "Ability whose modifier drives initiative. Typically 'dexterity'.",
        +          "type": "string"
        +        },
        +        "misc": {
        +          "description": "Misc bonus added to initiative beyond the attribute modifier.",
        +          "type": "number"
        +        }
        +      },
        +      "type": "object"
        +    },
        +    "perception": {
        +      "additionalProperties": {},
        +      "properties": {
        +        "attribute": {
        +          "type": "string"
        +        },
        +        "misc": {
        +          "type": "number"
        +        },
        +        "proficiency": {
        +          "type": "number"
        +        }
        +      },
        +      "type": "object"
        +    },
        +    "spellCasting": {
        +      "additionalProperties": {},
        +      "properties": {
        +        "attribute": {
        +          "type": "string"
        +        },
        +        "misc": {
        +          "type": "number"
        +        },
        +        "proficiency": {
        +          "type": "number"
        +        }
        +      },
        +      "type": "object"
        +    }
        +  },
        +  "type": "object"
        +}
      • addedInput schema / properties / personality
        Added value: +{
        +  "additionalProperties": {},
        +  "properties": {
        +    "bonds": {
        +      "type": "string"
        +    },
        +    "flaws": {
        +      "type": "string"
        +    },
        +    "ideals": {
        +      "type": "string"
        +    },
        +    "traits": {
        +      "type": "string"
        +    }
        +  },
        +  "type": "object"
        +}
      • addedInput schema / properties / rules
        Added value: +{
        +  "items": {
        +    "additionalProperties": {},
        +    "properties": {
        +      "_ref": {
        +        "description": "Master Rule ObjectId. Present when the snapshot points at a Vault Rule (PC catalog content); null on stock-monster-style inline rules.",
        +        "minLength": 1,
        +        "type": "string"
        +      },
        +      "actions": {
        +        "type": "string"
        +      },
        +      "description": {
        +        "type": "string"
        +      },
        +      "detail": {
        +        "type": "string"
        +      },
        +      "level": {
        +        "description": "Per-instance class level (this character's level in this class) — only meaningful on a Class snapshot. Stored and read directly, never derived; total character level stays XP-derived. Absent on non-Class snapshots.",
        +        "type": "number"
        +      },
        +      "name": {
        +        "type": "string"
        +      },
        +      "statBonuses": {
        +        "items": {
        +          "additionalProperties": {},
        +          "properties": {
        +            "attribute": {
        +              "description": "For valueType: 'attribute' — which ability's modifier to use.",
        +              "type": "string"
        +            },
        +            "audience": {
        +              "description": "Who the bonus contributes to. Absent = self.",
        +              "enum": [
        +                "self",
        +                "ally",
        +                "any",
        +                "target",
        +                "enemy"
        +              ],
        +              "type": "string"
        +            },
        +            "dice": {
        +              "description": "For valueType: 'dice' — dice expression (e.g. '1d4').",
        +              "type": "string"
        +            },
        +            "durationCount": {
        +              "description": "Numeric count paired with durationUnit (e.g. count: 3, unit: 'round').",
        +              "maximum": 9007199254740991,
        +              "minimum": 0,
        +              "type": "integer"
        +            },
        +            "durationUnit": {
        +              "description": "How long the bonus persists once fired. Only meaningful for event-driven bonuses.",
        +              "enum": [
        +                "instantaneous",
        +                "untilStartOfNextTurn",
        +                "untilEndOfNextTurn",
        +                "round",
        +                "minute",
        +                "hour",
        +                "untilShortRest",
        +                "untilLongRest"
        +              ],
        +              "type": "string"
        +            },
        +            "fixed": {
        +              "description": "For valueType: 'fixed' — the literal numeric contribution.",
        +              "type": "number"
        +            },
        +            "progression": {
        +              "description": "For valueType: 'byLevel' — per-level rows; walker picks the row with level <= current level.",
        +              "items": {
        +                "additionalProperties": {},
        +                "properties": {
        +                  "dice": {
        +                    "type": "string"
        +                  },
        +                  "flat": {
        +                    "type": "number"
        +                  },
        +                  "level": {
        +                    "maximum": 20,
        +                    "minimum": 1,
        +                    "type": "integer"
        +                  }
        +                },
        +                "type": "object"
        +              },
        +              "type": "array"
        +            },
        +            "range": {
        +              "description": "Aura radius in feet for ally/any-audience bonuses (Aura of Protection's 10 ft.). Absent = no range filter.",
        +              "maximum": 9007199254740991,
        +              "minimum": 0,
        +              "type": "integer"
        +            },
        +            "requires": {
        +              "description": "Optional predicate list that gates this bonus. Absent / empty = always-on.",
        +              "items": {
        +                "additionalProperties": {},
        +                "properties": {
        +                  "armorCategories": {
        +                    "description": "For 'equipped' + slot:armor: armor category list (Light / Medium / Heavy). OR semantics — match any.",
        +                    "items": {
        +                      "type": "string"
        +                    },
        +                    "type": "array"
        +                  },
        +                  "condition": {
        +                    "description": "For 'condition' predicates: the character-state condition to gate on (5e24 named conditions and ongoing-action states).",
        +                    "enum": [
        +                      "blinded",
        +                      "charmed",
        +                      "dazed",
        +                      "deafened",
        +                      "exhaustion",
        +                      "frightened",
        +                      "grappled",
        +                      "incapacitated",
        +                      "invisible",
        +                      "paralyzed",
        +                      "petrified",
        +                      "poisoned",
        +                      "prone",
        +                      "restrained",
        +                      "stunned",
        +                      "unconscious",
        +                      "concentrating",
        +                      "grappling",
        +                      "dodging",
        +                      "hiding",
        +                      "raging"
        +                    ],
        +                    "type": "string"
        +                  },
        +                  "equipSlot": {
        +                    "description": "Body slot the matched weapon must occupy. mainHand / offHand. Resolved via getRequiredSlots so two-handed grips occupy both.",
        +                    "enum": [
        +                      "mainHand",
        +                      "offHand"
        +                    ],
        +                    "type": "string"
        +                  },
        +                  "negate": {
        +                    "description": "true inverts the predicate — 'while NOT matching' instead of 'while matching'.",
        +                    "type": "boolean"
        +                  },
        +                  "slot": {
        +                    "description": "For 'equipped' predicates: the body category to match (armor / shield / weapon).",
        +                    "enum": [
        +                      "armor",
        +                      "shield",
        +                      "weapon"
        +                    ],
        +                    "type": "string"
        +                  },
        +                  "type": {
        +                    "description": "Predicate type. 'equipped' = character-scoped (gates on what's equipped). 'attackingWeapon' = attack-scoped (gates on the current action's source weapon). 'condition' = gates on a character-state condition.",
        +                    "enum": [
        +                      "equipped",
        +                      "attackingWeapon",
        +                      "condition"
        +                    ],
        +                    "type": "string"
        +                  },
        +                  "weaponProperties": {
        +                    "description": "For 'equipped' + slot:weapon OR 'attackingWeapon': weapon-property list. AND semantics — match all.",
        +                    "items": {
        +                      "type": "string"
        +                    },
        +                    "type": "array"
        +                  }
        +                },
        +                "type": "object"
        +              },
        +              "type": "array"
        +            },
        +            "requiresLogic": {
        +              "description": "How `requires` predicates compose. 'and' (default) = ALL must hold. 'or' = ANY one is sufficient.",
        +              "enum": [
        +                "and",
        +                "or"
        +              ],
        +              "type": "string"
        +            },
        +            "target": {
        +              "description": "Stat the bonus contributes to (e.g. 'skills.Acrobatics.misc', 'attributes.strength.misc').",
        +              "type": "string"
        +            },
        +            "trigger": {
        +              "description": "Action-economy / cost shape of the bonus. passive / toggled / reaction / perRoll / resource / targetBound.",
        +              "enum": [
        +                "passive",
        +                "toggled",
        +                "reaction",
        +                "perRoll",
        +                "resource",
        +                "targetBound"
        +              ],
        +              "type": "string"
        +            },
        +            "triggerEvent": {
        +              "description": "Game-time event that fires the bonus (onHit / onDamage / startOfYourTurn / etc.). Absent = not event-driven (passive walker contributes whenever `requires` holds).",
        +              "enum": [
        +                "onHit",
        +                "onMiss",
        +                "onDamage",
        +                "startOfYourTurn",
        +                "endOfYourTurn",
        +                "startOfTargetTurn",
        +                "endOfTargetTurn"
        +              ],
        +              "type": "string"
        +            },
        +            "types": {
        +              "description": "Damage type tags for damage.* targets. No-op for non-damage targets.",
        +              "items": {
        +                "type": "string"
        +              },
        +              "type": "array"
        +            },
        +            "valueType": {
        +              "description": "How the contribution is computed. 'fixed' uses `fixed`; 'attribute' uses the mod of `attribute`; 'attackAttribute' uses the action's attack-roll ability (per-attack only); others scale by level/PB/dice.",
        +              "enum": [
        +                "fixed",
        +                "attribute",
        +                "proficiency",
        +                "level",
        +                "halfLevel",
        +                "dice",
        +                "byLevel",
        +                "attackAttribute"
        +              ],
        +              "type": "string"
        +            }
        +          },
        +          "type": "object"
        +        },
        +        "type": "array"
        +      },
        +      "stock": {
        +        "type": "boolean"
        +      },
        +      "summary": {
        +        "type": "string"
        +      },
        +      "type": {
        +        "description": "Rule type (Ability / Feat / Class / Background / etc.). Vault validates against its rulestype enum on save.",
        +        "type": "string"
        +      }
        +    },
        +    "type": "object"
        +  },
        +  "type": "array"
        +}
      • addedInput schema / properties / ruleset
        Added value: +{
        +  "description": "Ruleset code (e.g. '5th Edition', '5e24', 'PFRPG', 'Savage Worlds'). Restricted rulesets require an entitlement grant on the account — vault answers 403 for ungranted or unknown codes. Check list_rulesets for the codes this account can use.",
        +  "type": "string"
        +}
      • addedInput schema / properties / settings
        Added value: +{
        +  "additionalProperties": {},
        +  "properties": {
        +    "autoPassiveBonuses": {
        +      "description": "When true, the per-character rules engine layer contributes statBonuses from rules / items / feats. On 5e24 it ALSO derives the armor/shield rows of defense.armorClass from equipped items, recomputed on every sheet load — manual writes to those rows do not stick while this is true. Monsters should set this to false.",
        +      "type": "boolean"
        +    },
        +    "hiddenSections": {
        +      "description": "Sheet-section keys the player chose to hide while the section is empty ('spells', 'abilities', 'feats', 'origin', 'actionCards', 'hindrances', 'edges', 'stunts', 'extras'). A section with content always renders regardless of this list — the preference means 'hide when empty', never 'hide my data'.",
        +      "items": {
        +        "maxLength": 64,
        +        "type": "string"
        +      },
        +      "maxItems": 20,
        +      "type": "array"
        +    }
        +  },
        +  "type": "object"
        +}
      • addedInput schema / properties / skills
        Added value: +{
        +  "items": {
        +    "additionalProperties": {},
        +    "properties": {
        +      "attribute": {
        +        "type": "string"
        +      },
        +      "classSkill": {
        +        "type": "boolean"
        +      },
        +      "description": {
        +        "type": "string"
        +      },
        +      "expertise": {
        +        "type": "boolean"
        +      },
        +      "misc": {
        +        "type": "number"
        +      },
        +      "name": {
        +        "type": "string"
        +      },
        +      "passiveMisc": {
        +        "type": "number"
        +      },
        +      "proficiency": {
        +        "type": "number"
        +      },
        +      "proficient": {
        +        "type": "boolean"
        +      },
        +      "ranks": {
        +        "type": "number"
        +      },
        +      "rating": {
        +        "description": "Fate: ladder position, -2 (Terrible) to +8 (Legendary); also an FAE approach's rating. Demon Hunters: the trait's die size (4, 6, 8, 10, or 12), or 0 for an unrated Fringe discipline.",
        +        "type": "number"
        +      },
        +      "score": {
        +        "type": "number"
        +      }
        +    },
        +    "type": "object"
        +  },
        +  "type": "array"
        +}
      • addedInput schema / properties / speed
        Added value: +{
        +  "additionalProperties": {},
        +  "properties": {
        +    "base": {
        +      "description": "Walking speed in feet.",
        +      "type": "number"
        +    },
        +    "burrow": {
        +      "type": "number"
        +    },
        +    "climb": {
        +      "type": "number"
        +    },
        +    "fly": {
        +      "type": "number"
        +    },
        +    "swim": {
        +      "type": "number"
        +    }
        +  },
        +  "type": "object"
        +}
      • addedInput schema / properties / spells
        Added value: +{
        +  "items": {
        +    "additionalProperties": {},
        +    "properties": {
        +      "_ref": {
        +        "description": "Mongo `_id` reference (24-character hex string).",
        +        "minLength": 1,
        +        "type": "string"
        +      },
        +      "actions": {
        +        "type": "string"
        +      },
        +      "atWill": {
        +        "description": "Free-cast budget. true = the spell casts without a slot an unlimited number of times (rendered as an 'at will' badge, no use counter); a finite free cast uses maximum/current instead. Absent = an ordinary spell.",
        +        "type": "boolean"
        +      },
        +      "castingAbility": {
        +        "description": "Per-spell spellcasting-ability override (lowercase), stamped at build from the granting block's castingAbility / the player's pick. The sheet computes THIS spell's save DC / attack bonus from it. Absent = the spell uses the character-wide casting ability.",
        +        "enum": [
        +          "strength",
        +          "dexterity",
        +          "constitution",
        +          "intelligence",
        +          "wisdom",
        +          "charisma"
        +        ],
        +        "type": "string"
        +      },
        +      "current": {
        +        "type": "number"
        +      },
        +      "description": {
        +        "type": "string"
        +      },
        +      "detail": {
        +        "type": "string"
        +      },
        +      "level": {
        +        "type": "number"
        +      },
        +      "maximum": {
        +        "type": "number"
        +      },
        +      "name": {
        +        "type": "string"
        +      },
        +      "prepared": {
        +        "type": "boolean"
        +      },
        +      "rank": {
        +        "type": "string"
        +      },
        +      "recovery": {
        +        "description": "Per-rest recovery rows for a finite free-cast counter, stamped from the granting rule's freeCast.recovery whenever the counter is created or grown (creation build and level-up). The vault rest control refills the counter from these when the player declares a Short/Long rest. Absent = the counter doesn't refresh on rest.",
        +        "items": {
        +          "additionalProperties": {},
        +          "properties": {
        +            "count": {
        +              "maximum": 9007199254740991,
        +              "minimum": 0,
        +              "type": "integer"
        +            },
        +            "on": {
        +              "enum": [
        +                "Short",
        +                "Long"
        +              ],
        +              "type": "string"
        +            },
        +            "restoreAll": {
        +              "type": "boolean"
        +            }
        +          },
        +          "type": "object"
        +        },
        +        "type": "array"
        +      },
        +      "school": {
        +        "type": "string"
        +      },
        +      "stock": {
        +        "type": "boolean"
        +      },
        +      "summary": {
        +        "type": "string"
        +      }
        +    },
        +    "type": "object"
        +  },
        +  "type": "array"
        +}
      • addedInput schema / properties / stress
        Added value: +{
        +  "items": {
        +    "additionalProperties": {},
        +    "properties": {
        +      "boxes": {
        +        "items": {
        +          "additionalProperties": {},
        +          "properties": {
        +            "marked": {
        +              "type": "boolean"
        +            },
        +            "value": {
        +              "description": "Shifts this box absorbs. Stated per box, not implied by its position.",
        +              "type": "number"
        +            }
        +          },
        +          "type": "object"
        +        },
        +        "type": "array"
        +      },
        +      "name": {
        +        "description": "Track name — 'Physical Stress' / 'Mental Stress' in Fate Core, 'Stress' in Fate Accelerated.",
        +        "type": "string"
        +      }
        +    },
        +    "type": "object"
        +  },
        +  "type": "array"
        +}
      • addedInput schema / properties / trackables
        Added value: +{
        +  "items": {
        +    "additionalProperties": {},
        +    "properties": {
        +      "_rule": {
        +        "description": "Mongo `_id` reference (24-character hex string).",
        +        "minLength": 1,
        +        "type": "string"
        +      },
        +      "_spell": {
        +        "description": "The Spell this trackable is a free-cast budget for (a spell grant's `freeCast`). Present means 'N casts of this spell without a slot'; the sheet surfaces it on that spell. Absent on every other trackable.",
        +        "minLength": 1,
        +        "type": "string"
        +      },
        +      "current": {
        +        "maximum": 9007199254740991,
        +        "minimum": -9007199254740991,
        +        "type": "integer"
        +      },
        +      "description": {
        +        "type": "string"
        +      },
        +      "maximum": {
        +        "maximum": 9007199254740991,
        +        "minimum": -9007199254740991,
        +        "type": "integer"
        +      },
        +      "name": {
        +        "type": "string"
        +      },
        +      "recovery": {
        +        "items": {
        +          "additionalProperties": {},
        +          "properties": {
        +            "count": {
        +              "maximum": 9007199254740991,
        +              "minimum": 0,
        +              "type": "integer"
        +            },
        +            "on": {
        +              "enum": [
        +                "Short",
        +                "Long"
        +              ],
        +              "type": "string"
        +            },
        +            "restoreAll": {
        +              "type": "boolean"
        +            }
        +          },
        +          "type": "object"
        +        },
        +        "type": "array"
        +      },
        +      "slotLevel": {
        +        "description": "Spell-slot level of this pool (Pact Magic: one pool whose level rises with character level), stamped at build from the granting rule's uses[].slotLevel. The sheet shows it on the trackable row ('Level N'). Absent = an ordinary counter.",
        +        "maximum": 9,
        +        "minimum": 1,
        +        "type": "integer"
        +      },
        +      "type": {
        +        "description": "'number' (counter) or 'checkboxes' (filled boxes). Defaults to 'number'.",
        +        "type": "string"
        +      }
        +    },
        +    "type": "object"
        +  },
        +  "type": "array"
        +}
      • addedInput schema / properties / type
        Added value: +{
        +  "description": "Character type. Free-form per ruleset. Set to 'monster' (lowercase) to mark an authored monster; vault's character list endpoint filters that value out of the default catalog view.",
        +  "type": "string"
        +}
      • addedInput schema / required
        Added value: +[
        +  "id",
        +  "baseUpdatedAt"
        +]
    • Changedvault_update_companion_state6 fields changed
      • addedInput schema / $schema
        Added value: +"http://json-schema.org/draft-07/schema#"
      • addedInput schema / properties / baseUpdatedAt
        Added value: +{
        +  "description": "REQUIRED proof that you are working from the latest version: copy the `updatedAt` value verbatim from a FRESH read of this exact record (use the matching get tool first). Values from memory, from an earlier conversation, or guessed timestamps are rejected with OUT_OF_SYNC and nothing is written. After a successful update, the response carries the new `updatedAt` — use that for any follow-up write.",
        +  "minLength": 1,
        +  "type": "string"
        +}
      • addedInput schema / properties / companionId
        Added value: +{
        +  "description": "The companion ROW's `_id` from the Main character's `companions[]` array — NOT the buddy character's own `_id`.",
        +  "minLength": 1,
        +  "type": "string"
        +}
      • addedInput schema / properties / id
        Added value: +{
        +  "description": "Mongo `_id` of the Main character carrying the companion row.",
        +  "minLength": 1,
        +  "type": "string"
        +}
      • addedInput schema / properties / state
        Added value: +{
        +  "additionalProperties": {},
        +  "description": "The row's complete replacement overlay. ATOMIC: what you send replaces the stored `state` wholesale — vault_get_character first, modify the returned row's `state`, and send it back complete. Stores current values only; maximums always derive from the source character and are dropped if sent.",
        +  "properties": {
        +    "deathSaves": {
        +      "additionalProperties": {},
        +      "properties": {
        +        "failures": {
        +          "items": {
        +            "type": "string"
        +          },
        +          "type": "array"
        +        },
        +        "successes": {
        +          "items": {
        +            "type": "string"
        +          },
        +          "type": "array"
        +        }
        +      },
        +      "type": "object"
        +    },
        +    "dying": {
        +      "additionalProperties": {},
        +      "properties": {
        +        "current": {
        +          "type": "number"
        +        },
        +        "wounds": {
        +          "type": "number"
        +        }
        +      },
        +      "type": "object"
        +    },
        +    "exhaustion": {
        +      "description": "5e24 Exhaustion level (0-6) tracked locally for the buddy.",
        +      "maximum": 6,
        +      "minimum": 0,
        +      "type": "integer"
        +    },
        +    "health": {
        +      "additionalProperties": {},
        +      "properties": {
        +        "fatigue": {
        +          "type": "number"
        +        },
        +        "incapacitated": {
        +          "type": "boolean"
        +        },
        +        "wounds": {
        +          "type": "number"
        +        }
        +      },
        +      "type": "object"
        +    },
        +    "hitDice": {
        +      "additionalProperties": {},
        +      "properties": {
        +        "current": {
        +          "type": "number"
        +        },
        +        "pools": {
        +          "items": {
        +            "additionalProperties": {},
        +            "properties": {
        +              "current": {
        +                "maximum": 9007199254740991,
        +                "minimum": 0,
        +                "type": "integer"
        +              },
        +              "dice": {
        +                "description": "Die size of this pool, e.g. 'd10'. Must match a pool on the source character.",
        +                "type": "string"
        +              }
        +            },
        +            "type": "object"
        +          },
        +          "type": "array"
        +        }
        +      },
        +      "type": "object"
        +    },
        +    "hitPoints": {
        +      "additionalProperties": {},
        +      "properties": {
        +        "current": {
        +          "type": "number"
        +        },
        +        "temp": {
        +          "type": "number"
        +        }
        +      },
        +      "type": "object"
        +    },
        +    "spells": {
        +      "description": "Free-cast counter positions on the source's spell entries.",
        +      "items": {
        +        "additionalProperties": {},
        +        "properties": {
        +          "current": {
        +            "type": "number"
        +          },
        +          "sourceId": {
        +            "description": "The `_id` of the matching trackable / spell entry on the SOURCE character.",
        +            "minLength": 1,
        +            "type": "string"
        +          }
        +        },
        +        "type": "object"
        +      },
        +      "type": "array"
        +    },
        +    "stress": {
        +      "items": {
        +        "additionalProperties": {},
        +        "properties": {
        +          "boxes": {
        +            "items": {
        +              "additionalProperties": {},
        +              "properties": {
        +                "marked": {
        +                  "type": "boolean"
        +                },
        +                "sourceId": {
        +                  "description": "Mongo `_id` reference (24-character hex string).",
        +                  "minLength": 1,
        +                  "type": "string"
        +                }
        +              },
        +              "type": "object"
        +            },
        +            "type": "array"
        +          },
        +          "sourceId": {
        +            "description": "The `_id` of the matching stress track on the SOURCE character.",
        +            "minLength": 1,
        +            "type": "string"
        +          }
        +        },
        +        "type": "object"
        +      },
        +      "type": "array"
        +    },
        +    "trackables": {
        +      "items": {
        +        "additionalProperties": {},
        +        "properties": {
        +          "current": {
        +            "type": "number"
        +          },
        +          "sourceId": {
        +            "description": "The `_id` of the matching trackable / spell entry on the SOURCE character.",
        +            "minLength": 1,
        +            "type": "string"
        +          }
        +        },
        +        "type": "object"
        +      },
        +      "type": "array"
        +    }
        +  },
        +  "type": "object"
        +}
      • addedInput schema / required
        Added value: +[
        +  "id",
        +  "companionId",
        +  "baseUpdatedAt",
        +  "state"
        +]
    • Changedvault_update_item54 fields changed
      • addedInput schema / $schema
        Added value: +"http://json-schema.org/draft-07/schema#"
      • addedInput schema / additionalProperties
        Added value: +{}
      • addedInput schema / properties / _parent
        Added value: +{
        +  "description": "Parent item ObjectId for variant items.",
        +  "minLength": 1,
        +  "type": "string"
        +}
      • addedInput schema / properties / abilityScoreBump
        Added value: +{
        +  "additionalProperties": {},
        +  "properties": {
        +    "options": {
        +      "description": "Alternatives the player picks exactly ONE of (OR).",
        +      "items": {
        +        "additionalProperties": {},
        +        "properties": {
        +          "lines": {
        +            "description": "Lines that ALL apply when this option is chosen (AND).",
        +            "items": {
        +              "additionalProperties": {},
        +              "properties": {
        +                "amount": {
        +                  "description": "How much each chosen ability goes up (usually positive).",
        +                  "type": "number"
        +                },
        +                "count": {
        +                  "description": "How many distinct abilities this line raises.",
        +                  "maximum": 9007199254740991,
        +                  "minimum": 1,
        +                  "type": "integer"
        +                },
        +                "eligible": {
        +                  "description": "Pool to choose from. Empty / absent = any of the six.",
        +                  "items": {
        +                    "enum": [
        +                      "strength",
        +                      "dexterity",
        +                      "constitution",
        +                      "intelligence",
        +                      "wisdom",
        +                      "charisma"
        +                    ],
        +                    "type": "string"
        +                  },
        +                  "type": "array"
        +                },
        +                "max": {
        +                  "description": "Ceiling no chosen score may exceed after the bump (ASI = 20).",
        +                  "maximum": 9007199254740991,
        +                  "minimum": 1,
        +                  "type": "integer"
        +                }
        +              },
        +              "type": "object"
        +            },
        +            "type": "array"
        +          }
        +        },
        +        "type": "object"
        +      },
        +      "type": "array"
        +    }
        +  },
        +  "type": "object"
        +}
      • addedInput schema / properties / abilityScoreSet
        Added value: +{
        +  "items": {
        +    "additionalProperties": {},
        +    "properties": {
        +      "ability": {
        +        "enum": [
        +          "strength",
        +          "dexterity",
        +          "constitution",
        +          "intelligence",
        +          "wisdom",
        +          "charisma"
        +        ],
        +        "type": "string"
        +      },
        +      "value": {
        +        "description": "Score to set the ability to while in effect.",
        +        "maximum": 9007199254740991,
        +        "minimum": 1,
        +        "type": "integer"
        +      }
        +    },
        +    "type": "object"
        +  },
        +  "type": "array"
        +}
      • addedInput schema / properties / actionType
        Added value: +{
        +  "description": "Authoring hint — when set, the character sheet's rule modal shows an 'Add to Actions' button that mints an action row with this `type`.",
        +  "type": "string"
        +}
      • addedInput schema / properties / active
        Added value: +{
        +  "type": "boolean"
        +}
      • addedInput schema / properties / armorCategory
        Added value: +{
        +  "description": "Armor category ('Light', 'Medium', 'Heavy', 'Shield').",
        +  "type": "string"
        +}
      • addedInput schema / properties / armorClass
        Added value: +{
        +  "description": "Base AC value the armor provides.",
        +  "type": "number"
        +}
      • addedInput schema / properties / baseUpdatedAt
        Added value: +{
        +  "description": "REQUIRED proof that you are working from the latest version: copy the `updatedAt` value verbatim from a FRESH read of this exact record (use the matching get tool first). Values from memory, from an earlier conversation, or guessed timestamps are rejected with OUT_OF_SYNC and nothing is written. After a successful update, the response carries the new `updatedAt` — use that for any follow-up write.",
        +  "minLength": 1,
        +  "type": "string"
        +}
      • addedInput schema / properties / cost
        Added value: +{
        +  "description": "Cost in gold pieces (max 2 decimal places). Vault enforces non-negativity and precision.",
        +  "minimum": 0,
        +  "type": "number"
        +}
      • addedInput schema / properties / damage
        Added value: +{
        +  "additionalProperties": {},
        +  "properties": {
        +    "appliesTo": {
        +      "enum": [
        +        "melee",
        +        "ranged",
        +        "either"
        +      ],
        +      "type": "string"
        +    },
        +    "area": {
        +      "items": {
        +        "additionalProperties": {},
        +        "properties": {
        +          "shape": {
        +            "enum": [
        +              "cone",
        +              "line",
        +              "sphere",
        +              "cube",
        +              "cylinder",
        +              "emanation",
        +              "radius"
        +            ],
        +            "type": "string"
        +          },
        +          "size": {
        +            "minimum": 0,
        +            "type": "number"
        +          },
        +          "width": {
        +            "minimum": 0,
        +            "type": "number"
        +          }
        +        },
        +        "type": "object"
        +      },
        +      "type": "array"
        +    },
        +    "dice": {
        +      "type": "string"
        +    },
        +    "flat": {
        +      "type": "number"
        +    },
        +    "modifierAbility": {
        +      "enum": [
        +        "strength",
        +        "dexterity",
        +        "constitution",
        +        "intelligence",
        +        "wisdom",
        +        "charisma"
        +      ],
        +      "type": "string"
        +    },
        +    "modifierType": {
        +      "enum": [
        +        "flat",
        +        "proficiency",
        +        "ability"
        +      ],
        +      "type": "string"
        +    },
        +    "onSave": {
        +      "enum": [
        +        "half",
        +        "negates",
        +        "full"
        +      ],
        +      "type": "string"
        +    },
        +    "progression": {
        +      "items": {
        +        "additionalProperties": {},
        +        "properties": {
        +          "dice": {
        +            "type": "string"
        +          },
        +          "flat": {
        +            "type": "number"
        +          },
        +          "level": {
        +            "maximum": 20,
        +            "minimum": 1,
        +            "type": "integer"
        +          }
        +        },
        +        "type": "object"
        +      },
        +      "type": "array"
        +    },
        +    "save": {
        +      "additionalProperties": {},
        +      "properties": {
        +        "ability": {
        +          "enum": [
        +            "none",
        +            "spellcasting",
        +            "attackAttribute",
        +            "strength",
        +            "dexterity",
        +            "constitution",
        +            "intelligence",
        +            "wisdom",
        +            "charisma"
        +          ],
        +          "type": "string"
        +        },
        +        "dcBase": {
        +          "type": "number"
        +        },
        +        "includesProficiency": {
        +          "type": "boolean"
        +        },
        +        "saveType": {
        +          "enum": [
        +            "strength",
        +            "dexterity",
        +            "constitution",
        +            "intelligence",
        +            "wisdom",
        +            "charisma"
        +          ],
        +          "type": "string"
        +        }
        +      },
        +      "type": "object"
        +    },
        +    "scaling": {
        +      "enum": [
        +        "fixed",
        +        "byLevel",
        +        "spellSlot"
        +      ],
        +      "type": "string"
        +    },
        +    "scalingAttribute": {
        +      "type": "string"
        +    },
        +    "slotIncrement": {
        +      "additionalProperties": {},
        +      "properties": {
        +        "dice": {
        +          "type": "string"
        +        },
        +        "flat": {
        +          "type": "number"
        +        },
        +        "targets": {
        +          "maximum": 9007199254740991,
        +          "minimum": 1,
        +          "type": "integer"
        +        }
        +      },
        +      "type": "object"
        +    },
        +    "targets": {
        +      "additionalProperties": {},
        +      "properties": {
        +        "count": {
        +          "maximum": 9007199254740991,
        +          "minimum": 1,
        +          "type": "integer"
        +        }
        +      },
        +      "type": "object"
        +    },
        +    "trigger": {
        +      "enum": [
        +        "passive",
        +        "toggled",
        +        "reaction",
        +        "perRoll",
        +        "resource",
        +        "targetBound"
        +      ],
        +      "type": "string"
        +    },
        +    "types": {
        +      "items": {
        +        "type": "string"
        +      },
        +      "type": "array"
        +    }
        +  },
        +  "type": "object"
        +}
      • addedInput schema / properties / damageDice
        Added value: +{
        +  "description": "Base damage expression (e.g. '1d8').",
        +  "type": "string"
        +}
      • addedInput schema / properties / damageReduction
        Added value: +{
        +  "items": {
        +    "additionalProperties": {},
        +    "properties": {
        +      "amount": {
        +        "additionalProperties": {},
        +        "properties": {
        +          "dice": {
        +            "type": "string"
        +          },
        +          "flat": {
        +            "type": "number"
        +          },
        +          "includesProficiency": {
        +            "type": "boolean"
        +          },
        +          "modifierSource": {
        +            "enum": [
        +              "spellcasting",
        +              "attackAttribute",
        +              "strength",
        +              "dexterity",
        +              "constitution",
        +              "intelligence",
        +              "wisdom",
        +              "charisma"
        +            ],
        +            "type": "string"
        +          }
        +        },
        +        "type": "object"
        +      },
        +      "range": {
        +        "maximum": 9007199254740991,
        +        "minimum": 0,
        +        "type": "integer"
        +      },
        +      "requires": {
        +        "items": {
        +          "additionalProperties": {},
        +          "properties": {
        +            "armorCategories": {
        +              "description": "For 'equipped' + slot:armor: armor category list (Light / Medium / Heavy). OR semantics — match any.",
        +              "items": {
        +                "type": "string"
        +              },
        +              "type": "array"
        +            },
        +            "condition": {
        +              "description": "For 'condition' predicates: the character-state condition to gate on (5e24 named conditions and ongoing-action states).",
        +              "enum": [
        +                "blinded",
        +                "charmed",
        +                "dazed",
        +                "deafened",
        +                "exhaustion",
        +                "frightened",
        +                "grappled",
        +                "incapacitated",
        +                "invisible",
        +                "paralyzed",
        +                "petrified",
        +                "poisoned",
        +                "prone",
        +                "restrained",
        +                "stunned",
        +                "unconscious",
        +                "concentrating",
        +                "grappling",
        +                "dodging",
        +                "hiding",
        +                "raging"
        +              ],
        +              "type": "string"
        +            },
        +            "equipSlot": {
        +              "description": "Body slot the matched weapon must occupy. mainHand / offHand. Resolved via getRequiredSlots so two-handed grips occupy both.",
        +              "enum": [
        +                "mainHand",
        +                "offHand"
        +              ],
        +              "type": "string"
        +            },
        +            "negate": {
        +              "description": "true inverts the predicate — 'while NOT matching' instead of 'while matching'.",
        +              "type": "boolean"
        +            },
        +            "slot": {
        +              "description": "For 'equipped' predicates: the body category to match (armor / shield / weapon).",
        +              "enum": [
        +                "armor",
        +                "shield",
        +                "weapon"
        +              ],
        +              "type": "string"
        +            },
        +            "type": {
        +              "description": "Predicate type. 'equipped' = character-scoped (gates on what's equipped). 'attackingWeapon' = attack-scoped (gates on the current action's source weapon). 'condition' = gates on a character-state condition.",
        +              "enum": [
        +                "equipped",
        +                "attackingWeapon",
        +                "condition"
        +              ],
        +              "type": "string"
        +            },
        +            "weaponProperties": {
        +              "description": "For 'equipped' + slot:weapon OR 'attackingWeapon': weapon-property list. AND semantics — match all.",
        +              "items": {
        +                "type": "string"
        +              },
        +              "type": "array"
        +            }
        +          },
        +          "type": "object"
        +        },
        +        "type": "array"
        +      },
        +      "requiresLogic": {
        +        "enum": [
        +          "and",
        +          "or"
        +        ],
        +        "type": "string"
        +      },
        +      "target": {
        +        "enum": [
        +          "self",
        +          "ally",
        +          "any",
        +          "target",
        +          "enemy"
        +        ],
        +        "type": "string"
        +      },
        +      "trigger": {
        +        "enum": [
        +          "passive",
        +          "toggled",
        +          "reaction",
        +          "perRoll",
        +          "resource",
        +          "targetBound"
        +        ],
        +        "type": "string"
        +      },
        +      "types": {
        +        "items": {
        +          "type": "string"
        +        },
        +        "type": "array"
        +      }
        +    },
        +    "type": "object"
        +  },
        +  "type": "array"
        +}
      • addedInput schema / properties / damageType
        Added value: +{
        +  "description": "Damage types as an array of strings (most items have one type; some have multiples).",
        +  "items": {
        +    "type": "string"
        +  },
        +  "type": "array"
        +}
      • addedInput schema / properties / description
        Added value: +{
        +  "description": "Full item description. Markdown is supported.",
        +  "type": "string"
        +}
      • addedInput schema / properties / diceFloors
        Added value: +{
        +  "items": {
        +    "additionalProperties": {},
        +    "properties": {
        +      "appliesTo": {
        +        "enum": [
        +          "damage",
        +          "damage.melee",
        +          "damage.ranged",
        +          "damage.spell",
        +          "healing"
        +        ],
        +        "type": "string"
        +      },
        +      "floor": {
        +        "maximum": 9007199254740991,
        +        "minimum": 1,
        +        "type": "integer"
        +      },
        +      "requires": {
        +        "items": {
        +          "additionalProperties": {},
        +          "properties": {
        +            "armorCategories": {
        +              "description": "For 'equipped' + slot:armor: armor category list (Light / Medium / Heavy). OR semantics — match any.",
        +              "items": {
        +                "type": "string"
        +              },
        +              "type": "array"
        +            },
        +            "condition": {
        +              "description": "For 'condition' predicates: the character-state condition to gate on (5e24 named conditions and ongoing-action states).",
        +              "enum": [
        +                "blinded",
        +                "charmed",
        +                "dazed",
        +                "deafened",
        +                "exhaustion",
        +                "frightened",
        +                "grappled",
        +                "incapacitated",
        +                "invisible",
        +                "paralyzed",
        +                "petrified",
        +                "poisoned",
        +                "prone",
        +                "restrained",
        +                "stunned",
        +                "unconscious",
        +                "concentrating",
        +                "grappling",
        +                "dodging",
        +                "hiding",
        +                "raging"
        +              ],
        +              "type": "string"
        +            },
        +            "equipSlot": {
        +              "description": "Body slot the matched weapon must occupy. mainHand / offHand. Resolved via getRequiredSlots so two-handed grips occupy both.",
        +              "enum": [
        +                "mainHand",
        +                "offHand"
        +              ],
        +              "type": "string"
        +            },
        +            "negate": {
        +              "description": "true inverts the predicate — 'while NOT matching' instead of 'while matching'.",
        +              "type": "boolean"
        +            },
        +            "slot": {
        +              "description": "For 'equipped' predicates: the body category to match (armor / shield / weapon).",
        +              "enum": [
        +                "armor",
        +                "shield",
        +                "weapon"
        +              ],
        +              "type": "string"
        +            },
        +            "type": {
        +              "description": "Predicate type. 'equipped' = character-scoped (gates on what's equipped). 'attackingWeapon' = attack-scoped (gates on the current action's source weapon). 'condition' = gates on a character-state condition.",
        +              "enum": [
        +                "equipped",
        +                "attackingWeapon",
        +                "condition"
        +              ],
        +              "type": "string"
        +            },
        +            "weaponProperties": {
        +              "description": "For 'equipped' + slot:weapon OR 'attackingWeapon': weapon-property list. AND semantics — match all.",
        +              "items": {
        +                "type": "string"
        +              },
        +              "type": "array"
        +            }
        +          },
        +          "type": "object"
        +        },
        +        "type": "array"
        +      },
        +      "requiresLogic": {
        +        "enum": [
        +          "and",
        +          "or"
        +        ],
        +        "type": "string"
        +      },
        +      "threshold": {
        +        "maximum": 9007199254740991,
        +        "minimum": 1,
        +        "type": "integer"
        +      },
        +      "trigger": {
        +        "enum": [
        +          "passive",
        +          "toggled",
        +          "reaction",
        +          "perRoll",
        +          "resource",
        +          "targetBound"
        +        ],
        +        "type": "string"
        +      }
        +    },
        +    "type": "object"
        +  },
        +  "type": "array"
        +}
      • addedInput schema / properties / diceReplacements
        Added value: +{
        +  "items": {
        +    "additionalProperties": {},
        +    "properties": {
        +      "_target": {
        +        "description": "Mongo `_id` reference (24-character hex string).",
        +        "minLength": 1,
        +        "type": "string"
        +      },
        +      "dice": {
        +        "type": "string"
        +      },
        +      "progression": {
        +        "items": {
        +          "additionalProperties": {},
        +          "properties": {
        +            "dice": {
        +              "type": "string"
        +            },
        +            "level": {
        +              "maximum": 20,
        +              "minimum": 1,
        +              "type": "integer"
        +            }
        +          },
        +          "type": "object"
        +        },
        +        "type": "array"
        +      },
        +      "requires": {
        +        "items": {
        +          "additionalProperties": {},
        +          "properties": {
        +            "armorCategories": {
        +              "description": "For 'equipped' + slot:armor: armor category list (Light / Medium / Heavy). OR semantics — match any.",
        +              "items": {
        +                "type": "string"
        +              },
        +              "type": "array"
        +            },
        +            "condition": {
        +              "description": "For 'condition' predicates: the character-state condition to gate on (5e24 named conditions and ongoing-action states).",
        +              "enum": [
        +                "blinded",
        +                "charmed",
        +                "dazed",
        +                "deafened",
        +                "exhaustion",
        +                "frightened",
        +                "grappled",
        +                "incapacitated",
        +                "invisible",
        +                "paralyzed",
        +                "petrified",
        +                "poisoned",
        +                "prone",
        +                "restrained",
        +                "stunned",
        +                "unconscious",
        +                "concentrating",
        +                "grappling",
        +                "dodging",
        +                "hiding",
        +                "raging"
        +              ],
        +              "type": "string"
        +            },
        +            "equipSlot": {
        +              "description": "Body slot the matched weapon must occupy. mainHand / offHand. Resolved via getRequiredSlots so two-handed grips occupy both.",
        +              "enum": [
        +                "mainHand",
        +                "offHand"
        +              ],
        +              "type": "string"
        +            },
        +            "negate": {
        +              "description": "true inverts the predicate — 'while NOT matching' instead of 'while matching'.",
        +              "type": "boolean"
        +            },
        +            "slot": {
        +              "description": "For 'equipped' predicates: the body category to match (armor / shield / weapon).",
        +              "enum": [
        +                "armor",
        +                "shield",
        +                "weapon"
        +              ],
        +              "type": "string"
        +            },
        +            "type": {
        +              "description": "Predicate type. 'equipped' = character-scoped (gates on what's equipped). 'attackingWeapon' = attack-scoped (gates on the current action's source weapon). 'condition' = gates on a character-state condition.",
        +              "enum": [
        +                "equipped",
        +                "attackingWeapon",
        +                "condition"
        +              ],
        +              "type": "string"
        +            },
        +            "weaponProperties": {
        +              "description": "For 'equipped' + slot:weapon OR 'attackingWeapon': weapon-property list. AND semantics — match all.",
        +              "items": {
        +                "type": "string"
        +              },
        +              "type": "array"
        +            }
        +          },
        +          "type": "object"
        +        },
        +        "type": "array"
        +      },
        +      "requiresLogic": {
        +        "enum": [
        +          "and",
        +          "or"
        +        ],
        +        "type": "string"
        +      }
        +    },
        +    "type": "object"
        +  },
        +  "type": "array"
        +}
      • addedInput schema / properties / duration
        Added value: +{
        +  "additionalProperties": {},
        +  "properties": {
        +    "concentration": {
        +      "type": "boolean"
        +    },
        +    "count": {
        +      "maximum": 9007199254740991,
        +      "minimum": 0,
        +      "type": "integer"
        +    },
        +    "unit": {
        +      "enum": [
        +        "round",
        +        "minute",
        +        "hour",
        +        "day",
        +        "untilShortRest",
        +        "untilLongRest",
        +        "special"
        +      ],
        +      "type": "string"
        +    }
        +  },
        +  "type": "object"
        +}
      • addedInput schema / properties / effect
        Added value: +{
        +  "additionalProperties": {},
        +  "properties": {
        +    "audience": {
        +      "enum": [
        +        "self",
        +        "ally",
        +        "any",
        +        "target",
        +        "enemy"
        +      ],
        +      "type": "string"
        +    },
        +    "conditions": {
        +      "items": {
        +        "additionalProperties": {},
        +        "properties": {
        +          "applyWhen": {
        +            "enum": [
        +              "always",
        +              "onFail",
        +              "onSuccess"
        +            ],
        +            "type": "string"
        +          },
        +          "durationCount": {
        +            "maximum": 9007199254740991,
        +            "minimum": 0,
        +            "type": "integer"
        +          },
        +          "durationUnit": {
        +            "enum": [
        +              "round",
        +              "minute",
        +              "hour",
        +              "day",
        +              "untilShortRest",
        +              "untilLongRest",
        +              "special"
        +            ],
        +            "type": "string"
        +          },
        +          "name": {
        +            "type": "string"
        +          },
        +          "target": {
        +            "enum": [
        +              "self",
        +              "target"
        +            ],
        +            "type": "string"
        +          }
        +        },
        +        "type": "object"
        +      },
        +      "type": "array"
        +    },
        +    "save": {
        +      "additionalProperties": {},
        +      "properties": {
        +        "ability": {
        +          "enum": [
        +            "none",
        +            "spellcasting",
        +            "attackAttribute",
        +            "strength",
        +            "dexterity",
        +            "constitution",
        +            "intelligence",
        +            "wisdom",
        +            "charisma"
        +          ],
        +          "type": "string"
        +        },
        +        "dcBase": {
        +          "type": "number"
        +        },
        +        "includesProficiency": {
        +          "type": "boolean"
        +        },
        +        "saveType": {
        +          "enum": [
        +            "strength",
        +            "dexterity",
        +            "constitution",
        +            "intelligence",
        +            "wisdom",
        +            "charisma"
        +          ],
        +          "type": "string"
        +        }
        +      },
        +      "type": "object"
        +    },
        +    "triggerEvent": {
        +      "enum": [
        +        "onHit",
        +        "onMiss",
        +        "onDamage",
        +        "startOfYourTurn",
        +        "endOfYourTurn",
        +        "startOfTargetTurn",
        +        "endOfTargetTurn"
        +      ],
        +      "type": "string"
        +    }
        +  },
        +  "type": "object"
        +}
      • addedInput schema / properties / equipSlots
        Added value: +{
        +  "description": "Allowed equip slot ids (e.g. 'mainHand', 'offHand', 'body'). Vocabulary is ruleset-specific.",
        +  "items": {
        +    "type": "string"
        +  },
        +  "type": "array"
        +}
      • addedInput schema / properties / forcedMovement
        Added value: +{
        +  "items": {
        +    "additionalProperties": {},
        +    "properties": {
        +      "audience": {
        +        "enum": [
        +          "self",
        +          "ally",
        +          "any",
        +          "target",
        +          "enemy"
        +        ],
        +        "type": "string"
        +      },
        +      "direction": {
        +        "enum": [
        +          "awayFromSelf",
        +          "towardSelf",
        +          "anywhere"
        +        ],
        +        "type": "string"
        +      },
        +      "distance": {
        +        "maximum": 9007199254740991,
        +        "minimum": 0,
        +        "type": "integer"
        +      },
        +      "maxTargetSize": {
        +        "enum": [
        +          "tiny",
        +          "small",
        +          "medium",
        +          "large",
        +          "huge",
        +          "gargantuan"
        +        ],
        +        "type": "string"
        +      },
        +      "requires": {
        +        "items": {
        +          "additionalProperties": {},
        +          "properties": {
        +            "armorCategories": {
        +              "description": "For 'equipped' + slot:armor: armor category list (Light / Medium / Heavy). OR semantics — match any.",
        +              "items": {
        +                "type": "string"
        +              },
        +              "type": "array"
        +            },
        +            "condition": {
        +              "description": "For 'condition' predicates: the character-state condition to gate on (5e24 named conditions and ongoing-action states).",
        +              "enum": [
        +                "blinded",
        +                "charmed",
        +                "dazed",
        +                "deafened",
        +                "exhaustion",
        +                "frightened",
        +                "grappled",
        +                "incapacitated",
        +                "invisible",
        +                "paralyzed",
        +                "petrified",
        +                "poisoned",
        +                "prone",
        +                "restrained",
        +                "stunned",
        +                "unconscious",
        +                "concentrating",
        +                "grappling",
        +                "dodging",
        +                "hiding",
        +                "raging"
        +              ],
        +              "type": "string"
        +            },
        +            "equipSlot": {
        +              "description": "Body slot the matched weapon must occupy. mainHand / offHand. Resolved via getRequiredSlots so two-handed grips occupy both.",
        +              "enum": [
        +                "mainHand",
        +                "offHand"
        +              ],
        +              "type": "string"
        +            },
        +            "negate": {
        +              "description": "true inverts the predicate — 'while NOT matching' instead of 'while matching'.",
        +              "type": "boolean"
        +            },
        +            "slot": {
        +              "description": "For 'equipped' predicates: the body category to match (armor / shield / weapon).",
        +              "enum": [
        +                "armor",
        +                "shield",
        +                "weapon"
        +              ],
        +              "type": "string"
        +            },
        +            "type": {
        +              "description": "Predicate type. 'equipped' = character-scoped (gates on what's equipped). 'attackingWeapon' = attack-scoped (gates on the current action's source weapon). 'condition' = gates on a character-state condition.",
        +              "enum": [
        +                "equipped",
        +                "attackingWeapon",
        +                "condition"
        +              ],
        +              "type": "string"
        +            },
        +            "weaponProperties": {
        +              "description": "For 'equipped' + slot:weapon OR 'attackingWeapon': weapon-property list. AND semantics — match all.",
        +              "items": {
        +                "type": "string"
        +              },
        +              "type": "array"
        +            }
        +          },
        +          "type": "object"
        +        },
        +        "type": "array"
        +      },
        +      "requiresLogic": {
        +        "enum": [
        +          "and",
        +          "or"
        +        ],
        +        "type": "string"
        +      },
        +      "triggerEvent": {
        +        "enum": [
        +          "onHit",
        +          "onMiss",
        +          "onDamage",
        +          "startOfYourTurn",
        +          "endOfYourTurn",
        +          "startOfTargetTurn",
        +          "endOfTargetTurn"
        +        ],
        +        "type": "string"
        +      }
        +    },
        +    "type": "object"
        +  },
        +  "type": "array"
        +}
      • addedInput schema / properties / healing
        Added value: +{
        +  "additionalProperties": {},
        +  "properties": {
        +    "dice": {
        +      "type": "string"
        +    },
        +    "flat": {
        +      "type": "number"
        +    },
        +    "modifierSource": {
        +      "enum": [
        +        "level",
        +        "spellcasting",
        +        "strength",
        +        "dexterity",
        +        "constitution",
        +        "intelligence",
        +        "wisdom",
        +        "charisma"
        +      ],
        +      "type": "string"
        +    },
        +    "progression": {
        +      "items": {
        +        "additionalProperties": {},
        +        "properties": {
        +          "dice": {
        +            "type": "string"
        +          },
        +          "flat": {
        +            "type": "number"
        +          },
        +          "level": {
        +            "maximum": 20,
        +            "minimum": 1,
        +            "type": "integer"
        +          }
        +        },
        +        "type": "object"
        +      },
        +      "type": "array"
        +    },
        +    "scaling": {
        +      "enum": [
        +        "fixed",
        +        "byLevel",
        +        "proficiency",
        +        "spellSlot"
        +      ],
        +      "type": "string"
        +    },
        +    "slotIncrement": {
        +      "additionalProperties": {},
        +      "properties": {
        +        "dice": {
        +          "type": "string"
        +        },
        +        "flat": {
        +          "type": "number"
        +        }
        +      },
        +      "type": "object"
        +    },
        +    "target": {
        +      "enum": [
        +        "self",
        +        "ally",
        +        "any",
        +        "multiple"
        +      ],
        +      "type": "string"
        +    },
        +    "targets": {
        +      "additionalProperties": {},
        +      "properties": {
        +        "count": {
        +          "maximum": 9007199254740991,
        +          "minimum": 1,
        +          "type": "integer"
        +        }
        +      },
        +      "type": "object"
        +    }
        +  },
        +  "type": "object"
        +}
      • addedInput schema / properties / id
        Added value: +{
        +  "description": "Mongo `_id` of the item to update.",
        +  "minLength": 1,
        +  "type": "string"
        +}
      • addedInput schema / properties / image
        Added value: +{
        +  "additionalProperties": {},
        +  "properties": {
        +    "url": {
        +      "description": "Image URL hosted on Embers Images (or any addressable HTTPS URL).",
        +      "type": "string"
        +    }
        +  },
        +  "type": "object"
        +}
      • addedInput schema / properties / mastery
        Added value: +{
        +  "description": "5e24 weapon mastery name (e.g. 'Topple', 'Vex', 'Slow').",
        +  "type": "string"
        +}
      • addedInput schema / properties / maxDexModifier
        Added value: +{
        +  "description": "Cap on DEX bonus from this armor (medium = 2; heavy = 0 typically).",
        +  "type": "number"
        +}
      • addedInput schema / properties / mechanicsKey
        Added value: +{
        +  "type": "string"
        +}
      • addedInput schema / properties / name
        Added value: +{
        +  "description": "Display name.",
        +  "minLength": 1,
        +  "type": "string"
        +}
      • addedInput schema / properties / ogl
        Added value: +{
        +  "type": "boolean"
        +}
      • addedInput schema / properties / parameters
        Added value: +{
        +  "items": {
        +    "additionalProperties": {},
        +    "properties": {
        +      "label": {
        +        "type": "string"
        +      },
        +      "max": {
        +        "type": "number"
        +      },
        +      "min": {
        +        "type": "number"
        +      },
        +      "name": {
        +        "type": "string"
        +      },
        +      "type": {
        +        "enum": [
        +          "number",
        +          "string",
        +          "enum"
        +        ],
        +        "type": "string"
        +      },
        +      "unit": {
        +        "type": "string"
        +      }
        +    },
        +    "type": "object"
        +  },
        +  "type": "array"
        +}
      • addedInput schema / properties / preparedSpells
        Added value: +{
        +  "additionalProperties": {},
        +  "properties": {
        +    "count": {
        +      "maximum": 9007199254740991,
        +      "minimum": 0,
        +      "type": "integer"
        +    },
        +    "progression": {
        +      "items": {
        +        "additionalProperties": {},
        +        "properties": {
        +          "count": {
        +            "maximum": 9007199254740991,
        +            "minimum": 0,
        +            "type": "integer"
        +          },
        +          "level": {
        +            "maximum": 20,
        +            "minimum": 1,
        +            "type": "integer"
        +          }
        +        },
        +        "type": "object"
        +      },
        +      "type": "array"
        +    }
        +  },
        +  "type": "object"
        +}
      • addedInput schema / properties / prerequisites
        Added value: +{
        +  "items": {
        +    "additionalProperties": {},
        +    "properties": {
        +      "abilities": {
        +        "description": "For abilityScore: ANY listed ability meeting `min` satisfies ('Str or Dex 13+').",
        +        "items": {
        +          "enum": [
        +            "strength",
        +            "dexterity",
        +            "constitution",
        +            "intelligence",
        +            "wisdom",
        +            "charisma"
        +          ],
        +          "type": "string"
        +        },
        +        "type": "array"
        +      },
        +      "category": {
        +        "description": "For rule (filter): matches any held rule in this category.",
        +        "type": "string"
        +      },
        +      "class": {
        +        "description": "For a `level` predicate: a Class rule id that scopes `min` to 'Nth level in that class'. Absent = total character level.",
        +        "minLength": 1,
        +        "type": "string"
        +      },
        +      "min": {
        +        "description": "Numeric minimum — character level (level), class level (class), or ability score (abilityScore).",
        +        "maximum": 9007199254740991,
        +        "minimum": 0,
        +        "type": "integer"
        +      },
        +      "negate": {
        +        "description": "true inverts the predicate — 'must NOT meet this'.",
        +        "type": "boolean"
        +      },
        +      "proficiency": {
        +        "description": "For proficiency: the proficiency name (e.g. 'Martial', 'Stealth').",
        +        "type": "string"
        +      },
        +      "proficiencyType": {
        +        "description": "For proficiency: the family.",
        +        "enum": [
        +          "skill",
        +          "tool",
        +          "weapon",
        +          "armor",
        +          "save",
        +          "language"
        +        ],
        +        "type": "string"
        +      },
        +      "rule": {
        +        "description": "For rule: a specific held Rule id.",
        +        "minLength": 1,
        +        "type": "string"
        +      },
        +      "ruleType": {
        +        "description": "For rule (filter): matches any held rule of this type.",
        +        "type": "string"
        +      },
        +      "spell": {
        +        "description": "For spell: a specific known Spell id.",
        +        "minLength": 1,
        +        "type": "string"
        +      },
        +      "spellList": {
        +        "description": "For spell (filter): knows any spell from this class list.",
        +        "type": "string"
        +      },
        +      "type": {
        +        "description": "Predicate kind: level / abilityScore / rule / spell / proficiency / spellcasting. (A class is required via a `rule` predicate pointing at the class rule.)",
        +        "enum": [
        +          "level",
        +          "abilityScore",
        +          "rule",
        +          "spell",
        +          "proficiency",
        +          "spellcasting"
        +        ],
        +        "type": "string"
        +      }
        +    },
        +    "type": "object"
        +  },
        +  "type": "array"
        +}
      • addedInput schema / properties / prerequisitesLogic
        Added value: +{
        +  "enum": [
        +    "and",
        +    "or"
        +  ],
        +  "type": "string"
        +}
      • addedInput schema / properties / proficiencyChoices
        Added value: +{
        +  "items": {
        +    "additionalProperties": {},
        +    "properties": {
        +      "allowedItems": {
        +        "items": {
        +          "type": "string"
        +        },
        +        "type": "array"
        +      },
        +      "level": {
        +        "enum": [
        +          "proficient",
        +          "expertise"
        +        ],
        +        "type": "string"
        +      },
        +      "mode": {
        +        "enum": [
        +          "specific",
        +          "all"
        +        ],
        +        "type": "string"
        +      },
        +      "progression": {
        +        "items": {
        +          "additionalProperties": {},
        +          "properties": {
        +            "count": {
        +              "maximum": 9007199254740991,
        +              "minimum": 0,
        +              "type": "integer"
        +            },
        +            "level": {
        +              "maximum": 20,
        +              "minimum": 1,
        +              "type": "integer"
        +            }
        +          },
        +          "type": "object"
        +        },
        +        "type": "array"
        +      },
        +      "types": {
        +        "items": {
        +          "enum": [
        +            "skill",
        +            "tool",
        +            "save",
        +            "weapon",
        +            "armor",
        +            "language"
        +          ],
        +          "type": "string"
        +        },
        +        "type": "array"
        +      }
        +    },
        +    "type": "object"
        +  },
        +  "type": "array"
        +}
      • addedInput schema / properties / properties
        Added value: +{
        +  "items": {
        +    "additionalProperties": {},
        +    "properties": {
        +      "ammoType": {
        +        "description": "Ammunition type for the Ammunition property (e.g. 'Arrow', 'Bolt').",
        +        "type": "string"
        +      },
        +      "damage": {
        +        "description": "Per-property damage dice override (e.g. Versatile's two-hand dice).",
        +        "type": "string"
        +      },
        +      "display": {
        +        "description": "Display string overriding the raw name.",
        +        "type": "string"
        +      },
        +      "name": {
        +        "description": "Property identifier (e.g. 'Finesse', 'Versatile', 'Ammunition').",
        +        "type": "string"
        +      },
        +      "range": {
        +        "additionalProperties": {},
        +        "description": "For ranged properties: normal / long reach in feet.",
        +        "properties": {
        +          "long": {
        +            "type": "number"
        +          },
        +          "normal": {
        +            "type": "number"
        +          }
        +        },
        +        "type": "object"
        +      }
        +    },
        +    "type": "object"
        +  },
        +  "type": "array"
        +}
      • addedInput schema / properties / publisher
        Added value: +{
        +  "type": "string"
        +}
      • addedInput schema / properties / recurringDamage
        Added value: +{
        +  "items": {
        +    "additionalProperties": {},
        +    "properties": {
        +      "amount": {
        +        "additionalProperties": {},
        +        "properties": {
        +          "dice": {
        +            "type": "string"
        +          },
        +          "flat": {
        +            "type": "number"
        +          },
        +          "includesProficiency": {
        +            "type": "boolean"
        +          },
        +          "modifierSource": {
        +            "enum": [
        +              "spellcasting",
        +              "attackAttribute",
        +              "strength",
        +              "dexterity",
        +              "constitution",
        +              "intelligence",
        +              "wisdom",
        +              "charisma"
        +            ],
        +            "type": "string"
        +          }
        +        },
        +        "type": "object"
        +      },
        +      "audience": {
        +        "enum": [
        +          "self",
        +          "ally",
        +          "any",
        +          "target",
        +          "enemy"
        +        ],
        +        "type": "string"
        +      },
        +      "durationCount": {
        +        "maximum": 9007199254740991,
        +        "minimum": 0,
        +        "type": "integer"
        +      },
        +      "durationUnit": {
        +        "enum": [
        +          "instantaneous",
        +          "untilStartOfNextTurn",
        +          "untilEndOfNextTurn",
        +          "round",
        +          "minute",
        +          "hour",
        +          "untilShortRest",
        +          "untilLongRest"
        +        ],
        +        "type": "string"
        +      },
        +      "ignoreResistances": {
        +        "type": "boolean"
        +      },
        +      "inheritDamageType": {
        +        "type": "boolean"
        +      },
        +      "range": {
        +        "maximum": 9007199254740991,
        +        "minimum": 0,
        +        "type": "integer"
        +      },
        +      "requires": {
        +        "items": {
        +          "additionalProperties": {},
        +          "properties": {
        +            "armorCategories": {
        +              "description": "For 'equipped' + slot:armor: armor category list (Light / Medium / Heavy). OR semantics — match any.",
        +              "items": {
        +                "type": "string"
        +              },
        +              "type": "array"
        +            },
        +            "condition": {
        +              "description": "For 'condition' predicates: the character-state condition to gate on (5e24 named conditions and ongoing-action states).",
        +              "enum": [
        +                "blinded",
        +                "charmed",
        +                "dazed",
        +                "deafened",
        +                "exhaustion",
        +                "frightened",
        +                "grappled",
        +                "incapacitated",
        +                "invisible",
        +                "paralyzed",
        +                "petrified",
        +                "poisoned",
        +                "prone",
        +                "restrained",
        +                "stunned",
        +                "unconscious",
        +                "concentrating",
        +                "grappling",
        +                "dodging",
        +                "hiding",
        +                "raging"
        +              ],
        +              "type": "string"
        +            },
        +            "equipSlot": {
        +              "description": "Body slot the matched weapon must occupy. mainHand / offHand. Resolved via getRequiredSlots so two-handed grips occupy both.",
        +              "enum": [
        +                "mainHand",
        +                "offHand"
        +              ],
        +              "type": "string"
        +            },
        +            "negate": {
        +              "description": "true inverts the predicate — 'while NOT matching' instead of 'while matching'.",
        +              "type": "boolean"
        +            },
        +            "slot": {
        +              "description": "For 'equipped' predicates: the body category to match (armor / shield / weapon).",
        +              "enum": [
        +                "armor",
        +                "shield",
        +                "weapon"
        +              ],
        +              "type": "string"
        +            },
        +            "type": {
        +              "description": "Predicate type. 'equipped' = character-scoped (gates on what's equipped). 'attackingWeapon' = attack-scoped (gates on the current action's source weapon). 'condition' = gates on a character-state condition.",
        +              "enum": [
        +                "equipped",
        +                "attackingWeapon",
        +                "condition"
        +              ],
        +              "type": "string"
        +            },
        +            "weaponProperties": {
        +              "description": "For 'equipped' + slot:weapon OR 'attackingWeapon': weapon-property list. AND semantics — match all.",
        +              "items": {
        +                "type": "string"
        +              },
        +              "type": "array"
        +            }
        +          },
        +          "type": "object"
        +        },
        +        "type": "array"
        +      },
        +      "requiresLogic": {
        +        "enum": [
        +          "and",
        +          "or"
        +        ],
        +        "type": "string"
        +      },
        +      "triggerEvent": {
        +        "enum": [
        +          "startOfYourTurn",
        +          "endOfYourTurn",
        +          "startOfTargetTurn",
        +          "endOfTargetTurn",
        +          "whenTargetEntersArea",
        +          "onHit",
        +          "onMiss",
        +          "onDamage"
        +        ],
        +        "type": "string"
        +      },
        +      "types": {
        +        "items": {
        +          "type": "string"
        +        },
        +        "type": "array"
        +      }
        +    },
        +    "type": "object"
        +  },
        +  "type": "array"
        +}
      • addedInput schema / properties / resistances
        Added value: +{
        +  "items": {
        +    "additionalProperties": {},
        +    "properties": {
        +      "mode": {
        +        "enum": [
        +          "resistance",
        +          "immunity",
        +          "vulnerability"
        +        ],
        +        "type": "string"
        +      },
        +      "range": {
        +        "description": "Aura radius in feet for ally/any-targeted resistances (Warding Aura's 10 ft.). Absent = self-only.",
        +        "maximum": 9007199254740991,
        +        "minimum": 0,
        +        "type": "integer"
        +      },
        +      "target": {
        +        "description": "Who the resistance protects — mirrors damageReduction's target/range pair. Absent = self.",
        +        "enum": [
        +          "self",
        +          "ally",
        +          "any",
        +          "target",
        +          "enemy"
        +        ],
        +        "type": "string"
        +      },
        +      "trigger": {
        +        "enum": [
        +          "passive",
        +          "toggled",
        +          "reaction",
        +          "perRoll",
        +          "resource",
        +          "targetBound"
        +        ],
        +        "type": "string"
        +      },
        +      "types": {
        +        "items": {
        +          "type": "string"
        +        },
        +        "type": "array"
        +      }
        +    },
        +    "type": "object"
        +  },
        +  "type": "array"
        +}
      • addedInput schema / properties / rollMods
        Added value: +{
        +  "items": {
        +    "additionalProperties": {},
        +    "properties": {
        +      "audience": {
        +        "enum": [
        +          "self",
        +          "ally",
        +          "any",
        +          "target",
        +          "enemy"
        +        ],
        +        "type": "string"
        +      },
        +      "consumeOnUse": {
        +        "type": "boolean"
        +      },
        +      "durationCount": {
        +        "maximum": 9007199254740991,
        +        "minimum": 0,
        +        "type": "integer"
        +      },
        +      "durationUnit": {
        +        "enum": [
        +          "instantaneous",
        +          "untilStartOfNextTurn",
        +          "untilEndOfNextTurn",
        +          "round",
        +          "minute",
        +          "hour",
        +          "untilShortRest",
        +          "untilLongRest"
        +        ],
        +        "type": "string"
        +      },
        +      "mode": {
        +        "enum": [
        +          "advantage",
        +          "disadvantage"
        +        ],
        +        "type": "string"
        +      },
        +      "range": {
        +        "maximum": 9007199254740991,
        +        "minimum": 0,
        +        "type": "integer"
        +      },
        +      "requires": {
        +        "items": {
        +          "additionalProperties": {},
        +          "properties": {
        +            "armorCategories": {
        +              "description": "For 'equipped' + slot:armor: armor category list (Light / Medium / Heavy). OR semantics — match any.",
        +              "items": {
        +                "type": "string"
        +              },
        +              "type": "array"
        +            },
        +            "condition": {
        +              "description": "For 'condition' predicates: the character-state condition to gate on (5e24 named conditions and ongoing-action states).",
        +              "enum": [
        +                "blinded",
        +                "charmed",
        +                "dazed",
        +                "deafened",
        +                "exhaustion",
        +                "frightened",
        +                "grappled",
        +                "incapacitated",
        +                "invisible",
        +                "paralyzed",
        +                "petrified",
        +                "poisoned",
        +                "prone",
        +                "restrained",
        +                "stunned",
        +                "unconscious",
        +                "concentrating",
        +                "grappling",
        +                "dodging",
        +                "hiding",
        +                "raging"
        +              ],
        +              "type": "string"
        +            },
        +            "equipSlot": {
        +              "description": "Body slot the matched weapon must occupy. mainHand / offHand. Resolved via getRequiredSlots so two-handed grips occupy both.",
        +              "enum": [
        +                "mainHand",
        +                "offHand"
        +              ],
        +              "type": "string"
        +            },
        +            "negate": {
        +              "description": "true inverts the predicate — 'while NOT matching' instead of 'while matching'.",
        +              "type": "boolean"
        +            },
        +            "slot": {
        +              "description": "For 'equipped' predicates: the body category to match (armor / shield / weapon).",
        +              "enum": [
        +                "armor",
        +                "shield",
        +                "weapon"
        +              ],
        +              "type": "string"
        +            },
        +            "type": {
        +              "description": "Predicate type. 'equipped' = character-scoped (gates on what's equipped). 'attackingWeapon' = attack-scoped (gates on the current action's source weapon). 'condition' = gates on a character-state condition.",
        +              "enum": [
        +                "equipped",
        +                "attackingWeapon",
        +                "condition"
        +              ],
        +              "type": "string"
        +            },
        +            "weaponProperties": {
        +              "description": "For 'equipped' + slot:weapon OR 'attackingWeapon': weapon-property list. AND semantics — match all.",
        +              "items": {
        +                "type": "string"
        +              },
        +              "type": "array"
        +            }
        +          },
        +          "type": "object"
        +        },
        +        "type": "array"
        +      },
        +      "requiresLogic": {
        +        "enum": [
        +          "and",
        +          "or"
        +        ],
        +        "type": "string"
        +      },
        +      "rollScope": {
        +        "enum": [
        +          "attack",
        +          "save",
        +          "abilityCheck",
        +          "skillCheck"
        +        ],
        +        "type": "string"
        +      },
        +      "trigger": {
        +        "enum": [
        +          "passive",
        +          "toggled",
        +          "reaction",
        +          "perRoll",
        +          "resource",
        +          "targetBound"
        +        ],
        +        "type": "string"
        +      },
        +      "triggerEvent": {
        +        "enum": [
        +          "onHit",
        +          "onMiss",
        +          "onDamage",
        +          "startOfYourTurn",
        +          "endOfYourTurn",
        +          "startOfTargetTurn",
        +          "endOfTargetTurn"
        +        ],
        +        "type": "string"
        +      }
        +    },
        +    "type": "object"
        +  },
        +  "type": "array"
        +}
      • addedInput schema / properties / ruleChoice
        Added value: +{
        +  "additionalProperties": {},
        +  "properties": {
        +    "allowedCategories": {
        +      "items": {
        +        "type": "string"
        +      },
        +      "type": "array"
        +    },
        +    "allowedRuleParameters": {
        +      "additionalProperties": {
        +        "additionalProperties": {},
        +        "properties": {
        +          "damageType": {
        +            "type": "string"
        +          },
        +          "number": {
        +            "maximum": 9007199254740991,
        +            "minimum": 0,
        +            "type": "integer"
        +          },
        +          "range": {
        +            "maximum": 9007199254740991,
        +            "minimum": 0,
        +            "type": "integer"
        +          },
        +          "speed": {
        +            "maximum": 9007199254740991,
        +            "minimum": 0,
        +            "type": "integer"
        +          }
        +        },
        +        "type": "object"
        +      },
        +      "propertyNames": {
        +        "type": "string"
        +      },
        +      "type": "object"
        +    },
        +    "allowedRules": {
        +      "items": {
        +        "description": "Mongo `_id` reference (24-character hex string).",
        +        "minLength": 1,
        +        "type": "string"
        +      },
        +      "type": "array"
        +    },
        +    "allowedTypes": {
        +      "items": {
        +        "type": "string"
        +      },
        +      "type": "array"
        +    },
        +    "count": {
        +      "maximum": 9007199254740991,
        +      "minimum": 0,
        +      "type": "integer"
        +    },
        +    "label": {
        +      "type": "string"
        +    },
        +    "mode": {
        +      "enum": [
        +        "filter",
        +        "specific"
        +      ],
        +      "type": "string"
        +    },
        +    "progression": {
        +      "items": {
        +        "additionalProperties": {},
        +        "properties": {
        +          "count": {
        +            "maximum": 9007199254740991,
        +            "minimum": 0,
        +            "type": "integer"
        +          },
        +          "level": {
        +            "maximum": 20,
        +            "minimum": 1,
        +            "type": "integer"
        +          }
        +        },
        +        "type": "object"
        +      },
        +      "type": "array"
        +    },
        +    "scaling": {
        +      "enum": [
        +        "fixed",
        +        "byLevel"
        +      ],
        +      "type": "string"
        +    }
        +  },
        +  "type": "object"
        +}
      • addedInput schema / properties / ruleset
        Added value: +{
        +  "description": "Ruleset code (e.g. '5th Edition', '5e24', 'PFRPG', 'Savage Worlds').",
        +  "type": "string"
        +}
      • addedInput schema / properties / source
        Added value: +{
        +  "type": "string"
        +}
      • addedInput schema / properties / spellChoices
        Added value: +{
        +  "items": {
        +    "additionalProperties": {},
        +    "properties": {
        +      "allowedCategories": {
        +        "items": {
        +          "type": "string"
        +        },
        +        "type": "array"
        +      },
        +      "allowedSchools": {
        +        "items": {
        +          "type": "string"
        +        },
        +        "type": "array"
        +      },
        +      "allowedSpells": {
        +        "items": {
        +          "description": "Mongo `_id` reference (24-character hex string).",
        +          "minLength": 1,
        +          "type": "string"
        +        },
        +        "type": "array"
        +      },
        +      "castingAbility": {
        +        "enum": [
        +          "strength",
        +          "dexterity",
        +          "constitution",
        +          "intelligence",
        +          "wisdom",
        +          "charisma"
        +        ],
        +        "type": "string"
        +      },
        +      "castingAbilityOptions": {
        +        "items": {
        +          "enum": [
        +            "strength",
        +            "dexterity",
        +            "constitution",
        +            "intelligence",
        +            "wisdom",
        +            "charisma"
        +          ],
        +          "type": "string"
        +        },
        +        "type": "array"
        +      },
        +      "freeCast": {
        +        "additionalProperties": {},
        +        "properties": {
        +          "atWill": {
        +            "type": "boolean"
        +          },
        +          "count": {
        +            "maximum": 9007199254740991,
        +            "minimum": 0,
        +            "type": "integer"
        +          },
        +          "progression": {
        +            "items": {
        +              "additionalProperties": {},
        +              "properties": {
        +                "count": {
        +                  "maximum": 9007199254740991,
        +                  "minimum": 0,
        +                  "type": "integer"
        +                },
        +                "level": {
        +                  "maximum": 20,
        +                  "minimum": 1,
        +                  "type": "integer"
        +                }
        +              },
        +              "type": "object"
        +            },
        +            "type": "array"
        +          },
        +          "recovery": {
        +            "items": {
        +              "additionalProperties": {},
        +              "properties": {
        +                "count": {
        +                  "maximum": 9007199254740991,
        +                  "minimum": 0,
        +                  "type": "integer"
        +                },
        +                "on": {
        +                  "enum": [
        +                    "Short",
        +                    "Long"
        +                  ],
        +                  "type": "string"
        +                },
        +                "restoreAll": {
        +                  "type": "boolean"
        +                }
        +              },
        +              "type": "object"
        +            },
        +            "type": "array"
        +          }
        +        },
        +        "type": "object"
        +      },
        +      "label": {
        +        "type": "string"
        +      },
        +      "maxLevel": {
        +        "maximum": 9,
        +        "minimum": 0,
        +        "type": "integer"
        +      },
        +      "minLevel": {
        +        "maximum": 9,
        +        "minimum": 0,
        +        "type": "integer"
        +      },
        +      "mode": {
        +        "enum": [
        +          "filter",
        +          "specific"
        +        ],
        +        "type": "string"
        +      },
        +      "prepared": {
        +        "type": "boolean"
        +      },
        +      "progression": {
        +        "items": {
        +          "additionalProperties": {},
        +          "properties": {
        +            "count": {
        +              "maximum": 9007199254740991,
        +              "minimum": 0,
        +              "type": "integer"
        +            },
        +            "level": {
        +              "maximum": 20,
        +              "minimum": 1,
        +              "type": "integer"
        +            }
        +          },
        +          "type": "object"
        +        },
        +        "type": "array"
        +      }
        +    },
        +    "type": "object"
        +  },
        +  "type": "array"
        +}
      • addedInput schema / properties / spellListChoices
        Added value: +{
        +  "items": {
        +    "additionalProperties": {},
        +    "properties": {
        +      "allowedCategories": {
        +        "items": {
        +          "type": "string"
        +        },
        +        "type": "array"
        +      },
        +      "castingAbility": {
        +        "enum": [
        +          "strength",
        +          "dexterity",
        +          "constitution",
        +          "intelligence",
        +          "wisdom",
        +          "charisma"
        +        ],
        +        "type": "string"
        +      },
        +      "castingAbilityOptions": {
        +        "items": {
        +          "enum": [
        +            "strength",
        +            "dexterity",
        +            "constitution",
        +            "intelligence",
        +            "wisdom",
        +            "charisma"
        +          ],
        +          "type": "string"
        +        },
        +        "type": "array"
        +      },
        +      "label": {
        +        "type": "string"
        +      },
        +      "picks": {
        +        "items": {
        +          "additionalProperties": {},
        +          "properties": {
        +            "count": {
        +              "maximum": 9007199254740991,
        +              "minimum": 0,
        +              "type": "integer"
        +            },
        +            "freeCast": {
        +              "additionalProperties": {},
        +              "properties": {
        +                "atWill": {
        +                  "type": "boolean"
        +                },
        +                "count": {
        +                  "maximum": 9007199254740991,
        +                  "minimum": 0,
        +                  "type": "integer"
        +                },
        +                "progression": {
        +                  "items": {
        +                    "additionalProperties": {},
        +                    "properties": {
        +                      "count": {
        +                        "maximum": 9007199254740991,
        +                        "minimum": 0,
        +                        "type": "integer"
        +                      },
        +                      "level": {
        +                        "maximum": 20,
        +                        "minimum": 1,
        +                        "type": "integer"
        +                      }
        +                    },
        +                    "type": "object"
        +                  },
        +                  "type": "array"
        +                },
        +                "recovery": {
        +                  "items": {
        +                    "additionalProperties": {},
        +                    "properties": {
        +                      "count": {
        +                        "maximum": 9007199254740991,
        +                        "minimum": 0,
        +                        "type": "integer"
        +                      },
        +                      "on": {
        +                        "enum": [
        +                          "Short",
        +                          "Long"
        +                        ],
        +                        "type": "string"
        +                      },
        +                      "restoreAll": {
        +                        "type": "boolean"
        +                      }
        +                    },
        +                    "type": "object"
        +                  },
        +                  "type": "array"
        +                }
        +              },
        +              "type": "object"
        +            },
        +            "label": {
        +              "type": "string"
        +            },
        +            "maxLevel": {
        +              "maximum": 9,
        +              "minimum": 0,
        +              "type": "integer"
        +            },
        +            "minLevel": {
        +              "maximum": 9,
        +              "minimum": 0,
        +              "type": "integer"
        +            }
        +          },
        +          "type": "object"
        +        },
        +        "type": "array"
        +      },
        +      "prepared": {
        +        "type": "boolean"
        +      }
        +    },
        +    "type": "object"
        +  },
        +  "type": "array"
        +}
      • addedInput schema / properties / statBonuses
        Added value: +{
        +  "items": {
        +    "additionalProperties": {},
        +    "properties": {
        +      "attribute": {
        +        "description": "For valueType: 'attribute' — which ability's modifier to use.",
        +        "type": "string"
        +      },
        +      "audience": {
        +        "description": "Who the bonus contributes to. Absent = self.",
        +        "enum": [
        +          "self",
        +          "ally",
        +          "any",
        +          "target",
        +          "enemy"
        +        ],
        +        "type": "string"
        +      },
        +      "dice": {
        +        "description": "For valueType: 'dice' — dice expression (e.g. '1d4').",
        +        "type": "string"
        +      },
        +      "durationCount": {
        +        "description": "Numeric count paired with durationUnit (e.g. count: 3, unit: 'round').",
        +        "maximum": 9007199254740991,
        +        "minimum": 0,
        +        "type": "integer"
        +      },
        +      "durationUnit": {
        +        "description": "How long the bonus persists once fired. Only meaningful for event-driven bonuses.",
        +        "enum": [
        +          "instantaneous",
        +          "untilStartOfNextTurn",
        +          "untilEndOfNextTurn",
        +          "round",
        +          "minute",
        +          "hour",
        +          "untilShortRest",
        +          "untilLongRest"
        +        ],
        +        "type": "string"
        +      },
        +      "fixed": {
        +        "description": "For valueType: 'fixed' — the literal numeric contribution.",
        +        "type": "number"
        +      },
        +      "progression": {
        +        "description": "For valueType: 'byLevel' — per-level rows; walker picks the row with level <= current level.",
        +        "items": {
        +          "additionalProperties": {},
        +          "properties": {
        +            "dice": {
        +              "type": "string"
        +            },
        +            "flat": {
        +              "type": "number"
        +            },
        +            "level": {
        +              "maximum": 20,
        +              "minimum": 1,
        +              "type": "integer"
        +            }
        +          },
        +          "type": "object"
        +        },
        +        "type": "array"
        +      },
        +      "range": {
        +        "description": "Aura radius in feet for ally/any-audience bonuses (Aura of Protection's 10 ft.). Absent = no range filter.",
        +        "maximum": 9007199254740991,
        +        "minimum": 0,
        +        "type": "integer"
        +      },
        +      "requires": {
        +        "description": "Optional predicate list that gates this bonus. Absent / empty = always-on.",
        +        "items": {
        +          "additionalProperties": {},
        +          "properties": {
        +            "armorCategories": {
        +              "description": "For 'equipped' + slot:armor: armor category list (Light / Medium / Heavy). OR semantics — match any.",
        +              "items": {
        +                "type": "string"
        +              },
        +              "type": "array"
        +            },
        +            "condition": {
        +              "description": "For 'condition' predicates: the character-state condition to gate on (5e24 named conditions and ongoing-action states).",
        +              "enum": [
        +                "blinded",
        +                "charmed",
        +                "dazed",
        +                "deafened",
        +                "exhaustion",
        +                "frightened",
        +                "grappled",
        +                "incapacitated",
        +                "invisible",
        +                "paralyzed",
        +                "petrified",
        +                "poisoned",
        +                "prone",
        +                "restrained",
        +                "stunned",
        +                "unconscious",
        +                "concentrating",
        +                "grappling",
        +                "dodging",
        +                "hiding",
        +                "raging"
        +              ],
        +              "type": "string"
        +            },
        +            "equipSlot": {
        +              "description": "Body slot the matched weapon must occupy. mainHand / offHand. Resolved via getRequiredSlots so two-handed grips occupy both.",
        +              "enum": [
        +                "mainHand",
        +                "offHand"
        +              ],
        +              "type": "string"
        +            },
        +            "negate": {
        +              "description": "true inverts the predicate — 'while NOT matching' instead of 'while matching'.",
        +              "type": "boolean"
        +            },
        +            "slot": {
        +              "description": "For 'equipped' predicates: the body category to match (armor / shield / weapon).",
        +              "enum": [
        +                "armor",
        +                "shield",
        +                "weapon"
        +              ],
        +              "type": "string"
        +            },
        +            "type": {
        +              "description": "Predicate type. 'equipped' = character-scoped (gates on what's equipped). 'attackingWeapon' = attack-scoped (gates on the current action's source weapon). 'condition' = gates on a character-state condition.",
        +              "enum": [
        +                "equipped",
        +                "attackingWeapon",
        +                "condition"
        +              ],
        +              "type": "string"
        +            },
        +            "weaponProperties": {
        +              "description": "For 'equipped' + slot:weapon OR 'attackingWeapon': weapon-property list. AND semantics — match all.",
        +              "items": {
        +                "type": "string"
        +              },
        +              "type": "array"
        +            }
        +          },
        +          "type": "object"
        +        },
        +        "type": "array"
        +      },
        +      "requiresLogic": {
        +        "description": "How `requires` predicates compose. 'and' (default) = ALL must hold. 'or' = ANY one is sufficient.",
        +        "enum": [
        +          "and",
        +          "or"
        +        ],
        +        "type": "string"
        +      },
        +      "target": {
        +        "description": "Stat the bonus contributes to (e.g. 'skills.Acrobatics.misc', 'attributes.strength.misc').",
        +        "type": "string"
        +      },
        +      "trigger": {
        +        "description": "Action-economy / cost shape of the bonus. passive / toggled / reaction / perRoll / resource / targetBound.",
        +        "enum": [
        +          "passive",
        +          "toggled",
        +          "reaction",
        +          "perRoll",
        +          "resource",
        +          "targetBound"
        +        ],
        +        "type": "string"
        +      },
        +      "triggerEvent": {
        +        "description": "Game-time event that fires the bonus (onHit / onDamage / startOfYourTurn / etc.). Absent = not event-driven (passive walker contributes whenever `requires` holds).",
        +        "enum": [
        +          "onHit",
        +          "onMiss",
        +          "onDamage",
        +          "startOfYourTurn",
        +          "endOfYourTurn",
        +          "startOfTargetTurn",
        +          "endOfTargetTurn"
        +        ],
        +        "type": "string"
        +      },
        +      "types": {
        +        "description": "Damage type tags for damage.* targets. No-op for non-damage targets.",
        +        "items": {
        +          "type": "string"
        +        },
        +        "type": "array"
        +      },
        +      "valueType": {
        +        "description": "How the contribution is computed. 'fixed' uses `fixed`; 'attribute' uses the mod of `attribute`; 'attackAttribute' uses the action's attack-roll ability (per-attack only); others scale by level/PB/dice.",
        +        "enum": [
        +          "fixed",
        +          "attribute",
        +          "proficiency",
        +          "level",
        +          "halfLevel",
        +          "dice",
        +          "byLevel",
        +          "attackAttribute"
        +        ],
        +        "type": "string"
        +      }
        +    },
        +    "type": "object"
        +  },
        +  "type": "array"
        +}
      • addedInput schema / properties / stealthDisadvantage
        Added value: +{
        +  "type": "boolean"
        +}
      • addedInput schema / properties / strengthRequirement
        Added value: +{
        +  "type": "number"
        +}
      • addedInput schema / properties / summary
        Added value: +{
        +  "description": "Short one-line summary.",
        +  "type": "string"
        +}
      • addedInput schema / properties / type
        Added value: +{
        +  "description": "Item type. Free-form per ruleset (Weapon, Armor, Tool, Adventuring Gear, Wondrous Item, etc.). Required at create.",
        +  "type": "string"
        +}
      • addedInput schema / properties / uses
        Added value: +{
        +  "items": {
        +    "additionalProperties": {},
        +    "properties": {
        +      "count": {
        +        "maximum": 9007199254740991,
        +        "minimum": 0,
        +        "type": "integer"
        +      },
        +      "mode": {
        +        "enum": [
        +          "fixed",
        +          "byLevel",
        +          "proficiency"
        +        ],
        +        "type": "string"
        +      },
        +      "name": {
        +        "type": "string"
        +      },
        +      "progression": {
        +        "items": {
        +          "additionalProperties": {},
        +          "properties": {
        +            "count": {
        +              "maximum": 9007199254740991,
        +              "minimum": 0,
        +              "type": "integer"
        +            },
        +            "countAbility": {
        +              "enum": [
        +                "strength",
        +                "dexterity",
        +                "constitution",
        +                "intelligence",
        +                "wisdom",
        +                "charisma"
        +              ],
        +              "type": "string"
        +            },
        +            "countSource": {
        +              "enum": [
        +                "fixed",
        +                "proficiency",
        +                "abilityMod"
        +              ],
        +              "type": "string"
        +            },
        +            "level": {
        +              "maximum": 20,
        +              "minimum": 1,
        +              "type": "integer"
        +            },
        +            "slotLevel": {
        +              "maximum": 9,
        +              "minimum": 1,
        +              "type": "integer"
        +            }
        +          },
        +          "type": "object"
        +        },
        +        "type": "array"
        +      },
        +      "recovery": {
        +        "items": {
        +          "additionalProperties": {},
        +          "properties": {
        +            "count": {
        +              "maximum": 9007199254740991,
        +              "minimum": 0,
        +              "type": "integer"
        +            },
        +            "on": {
        +              "enum": [
        +                "Short",
        +                "Long"
        +              ],
        +              "type": "string"
        +            },
        +            "restoreAll": {
        +              "type": "boolean"
        +            }
        +          },
        +          "type": "object"
        +        },
        +        "type": "array"
        +      },
        +      "rest": {
        +        "enum": [
        +          "Short",
        +          "Long"
        +        ],
        +        "type": "string"
        +      },
        +      "slotLevel": {
        +        "maximum": 9,
        +        "minimum": 1,
        +        "type": "integer"
        +      }
        +    },
        +    "type": "object"
        +  },
        +  "type": "array"
        +}
      • addedInput schema / properties / weaponType
        Added value: +{
        +  "description": "Weapon category ('Simple Melee', 'Martial Ranged', etc.).",
        +  "type": "string"
        +}
      • addedInput schema / properties / weight
        Added value: +{
        +  "type": "number"
        +}
      • addedInput schema / required
        Added value: +[
        +  "id",
        +  "baseUpdatedAt"
        +]
    • Changedvault_update_rule71 fields changed
      • addedInput schema / $schema
        Added value: +"http://json-schema.org/draft-07/schema#"
      • addedInput schema / additionalProperties
        Added value: +{}
      • addedInput schema / properties / _parent
        Added value: +{
        +  "description": "Mongo `_id` reference (24-character hex string).",
        +  "minLength": 1,
        +  "type": "string"
        +}
      • addedInput schema / properties / abilities
        Added value: +{
        +  "items": {
        +    "additionalProperties": {},
        +    "properties": {
        +      "_rule": {
        +        "description": "Granted Rule ObjectId.",
        +        "minLength": 1,
        +        "type": "string"
        +      },
        +      "level": {
        +        "maximum": 20,
        +        "minimum": 1,
        +        "type": "integer"
        +      },
        +      "parameterValues": {
        +        "additionalProperties": {},
        +        "properties": {
        +          "damageType": {
        +            "type": "string"
        +          },
        +          "number": {
        +            "maximum": 9007199254740991,
        +            "minimum": 0,
        +            "type": "integer"
        +          },
        +          "range": {
        +            "maximum": 9007199254740991,
        +            "minimum": 0,
        +            "type": "integer"
        +          },
        +          "speed": {
        +            "maximum": 9007199254740991,
        +            "minimum": 0,
        +            "type": "integer"
        +          }
        +        },
        +        "type": "object"
        +      }
        +    },
        +    "type": "object"
        +  },
        +  "type": "array"
        +}
      • addedInput schema / properties / abilityScoreBump
        Added value: +{
        +  "additionalProperties": {},
        +  "properties": {
        +    "options": {
        +      "description": "Alternatives the player picks exactly ONE of (OR).",
        +      "items": {
        +        "additionalProperties": {},
        +        "properties": {
        +          "lines": {
        +            "description": "Lines that ALL apply when this option is chosen (AND).",
        +            "items": {
        +              "additionalProperties": {},
        +              "properties": {
        +                "amount": {
        +                  "description": "How much each chosen ability goes up (usually positive).",
        +                  "type": "number"
        +                },
        +                "count": {
        +                  "description": "How many distinct abilities this line raises.",
        +                  "maximum": 9007199254740991,
        +                  "minimum": 1,
        +                  "type": "integer"
        +                },
        +                "eligible": {
        +                  "description": "Pool to choose from. Empty / absent = any of the six.",
        +                  "items": {
        +                    "enum": [
        +                      "strength",
        +                      "dexterity",
        +                      "constitution",
        +                      "intelligence",
        +                      "wisdom",
        +                      "charisma"
        +                    ],
        +                    "type": "string"
        +                  },
        +                  "type": "array"
        +                },
        +                "max": {
        +                  "description": "Ceiling no chosen score may exceed after the bump (ASI = 20).",
        +                  "maximum": 9007199254740991,
        +                  "minimum": 1,
        +                  "type": "integer"
        +                }
        +              },
        +              "type": "object"
        +            },
        +            "type": "array"
        +          }
        +        },
        +        "type": "object"
        +      },
        +      "type": "array"
        +    }
        +  },
        +  "type": "object"
        +}
      • addedInput schema / properties / abilityScoreSet
        Added value: +{
        +  "items": {
        +    "additionalProperties": {},
        +    "properties": {
        +      "ability": {
        +        "enum": [
        +          "strength",
        +          "dexterity",
        +          "constitution",
        +          "intelligence",
        +          "wisdom",
        +          "charisma"
        +        ],
        +        "type": "string"
        +      },
        +      "value": {
        +        "description": "Score to set the ability to while in effect.",
        +        "maximum": 9007199254740991,
        +        "minimum": 1,
        +        "type": "integer"
        +      }
        +    },
        +    "type": "object"
        +  },
        +  "type": "array"
        +}
      • addedInput schema / properties / abilityScores
        Added value: +{
        +  "items": {
        +    "type": "string"
        +  },
        +  "type": "array"
        +}
      • addedInput schema / properties / actionEconomy
        Added value: +{
        +  "description": "What invoking the ability costs on a turn: 'Action', 'Bonus Action', or 'Reaction'. Distinct from the mechanics actionType (a kind-of-action label). Absent = the ability takes the action.",
        +  "type": "string"
        +}
      • addedInput schema / properties / actionType
        Added value: +{
        +  "description": "Authoring hint — when set, the character sheet's rule modal shows an 'Add to Actions' button that mints an action row with this `type`.",
        +  "type": "string"
        +}
      • addedInput schema / properties / actions
        Added value: +{
        +  "description": "PF Playtest action-economy marker (F/1/2/3/R).",
        +  "type": "string"
        +}
      • addedInput schema / properties / active
        Added value: +{
        +  "type": "boolean"
        +}
      • addedInput schema / properties / age
        Added value: +{
        +  "type": "string"
        +}
      • addedInput schema / properties / armorTraining
        Added value: +{
        +  "items": {
        +    "type": "string"
        +  },
        +  "type": "array"
        +}
      • addedInput schema / properties / baseUpdatedAt
        Added value: +{
        +  "description": "REQUIRED proof that you are working from the latest version: copy the `updatedAt` value verbatim from a FRESH read of this exact record (use the matching get tool first). Values from memory, from an earlier conversation, or guessed timestamps are rejected with OUT_OF_SYNC and nothing is written. After a successful update, the response carries the new `updatedAt` — use that for any follow-up write.",
        +  "minLength": 1,
        +  "type": "string"
        +}
      • addedInput schema / properties / casterProgression
        Added value: +{
        +  "description": "How this class contributes to the combined multiclass spell-slot pool: full casters count every level, half/third round up, 'pact' (Pact Magic) keeps its own pool and never joins. Authorable on a base class or a subclass (a third-caster subclass carries it). Absent = non-caster.",
        +  "enum": [
        +    "full",
        +    "half",
        +    "third",
        +    "pact"
        +  ],
        +  "type": "string"
        +}
      • addedInput schema / properties / castingAbility
        Added value: +{
        +  "description": "The ability this rule's spellcasting keys off ('Intelligence is your spellcasting ability for your Wizard spells'). Author it on a class's Spellcasting ability rule; vault's creation and level-up wizards write it to the character-wide Spellcasting Ability (first-wins, never overwriting), and a multiclass whose ability differs stamps its granted spells per-entry. Distinct from a spell block's castingAbility, which overrides per grant. Absent = the rule says nothing about the character's casting ability.",
        +  "enum": [
        +    "strength",
        +    "dexterity",
        +    "constitution",
        +    "intelligence",
        +    "wisdom",
        +    "charisma"
        +  ],
        +  "type": "string"
        +}
      • addedInput schema / properties / categories
        Added value: +{
        +  "items": {
        +    "type": "string"
        +  },
        +  "type": "array"
        +}
      • addedInput schema / properties / creatureType
        Added value: +{
        +  "type": "string"
        +}
      • addedInput schema / properties / damage
        Added value: +{
        +  "additionalProperties": {},
        +  "properties": {
        +    "appliesTo": {
        +      "enum": [
        +        "melee",
        +        "ranged",
        +        "either"
        +      ],
        +      "type": "string"
        +    },
        +    "area": {
        +      "items": {
        +        "additionalProperties": {},
        +        "properties": {
        +          "shape": {
        +            "enum": [
        +              "cone",
        +              "line",
        +              "sphere",
        +              "cube",
        +              "cylinder",
        +              "emanation",
        +              "radius"
        +            ],
        +            "type": "string"
        +          },
        +          "size": {
        +            "minimum": 0,
        +            "type": "number"
        +          },
        +          "width": {
        +            "minimum": 0,
        +            "type": "number"
        +          }
        +        },
        +        "type": "object"
        +      },
        +      "type": "array"
        +    },
        +    "dice": {
        +      "type": "string"
        +    },
        +    "flat": {
        +      "type": "number"
        +    },
        +    "modifierAbility": {
        +      "enum": [
        +        "strength",
        +        "dexterity",
        +        "constitution",
        +        "intelligence",
        +        "wisdom",
        +        "charisma"
        +      ],
        +      "type": "string"
        +    },
        +    "modifierType": {
        +      "enum": [
        +        "flat",
        +        "proficiency",
        +        "ability"
        +      ],
        +      "type": "string"
        +    },
        +    "onSave": {
        +      "enum": [
        +        "half",
        +        "negates",
        +        "full"
        +      ],
        +      "type": "string"
        +    },
        +    "progression": {
        +      "items": {
        +        "additionalProperties": {},
        +        "properties": {
        +          "dice": {
        +            "type": "string"
        +          },
        +          "flat": {
        +            "type": "number"
        +          },
        +          "level": {
        +            "maximum": 20,
        +            "minimum": 1,
        +            "type": "integer"
        +          }
        +        },
        +        "type": "object"
        +      },
        +      "type": "array"
        +    },
        +    "save": {
        +      "additionalProperties": {},
        +      "properties": {
        +        "ability": {
        +          "enum": [
        +            "none",
        +            "spellcasting",
        +            "attackAttribute",
        +            "strength",
        +            "dexterity",
        +            "constitution",
        +            "intelligence",
        +            "wisdom",
        +            "charisma"
        +          ],
        +          "type": "string"
        +        },
        +        "dcBase": {
        +          "type": "number"
        +        },
        +        "includesProficiency": {
        +          "type": "boolean"
        +        },
        +        "saveType": {
        +          "enum": [
        +            "strength",
        +            "dexterity",
        +            "constitution",
        +            "intelligence",
        +            "wisdom",
        +            "charisma"
        +          ],
        +          "type": "string"
        +        }
        +      },
        +      "type": "object"
        +    },
        +    "scaling": {
        +      "enum": [
        +        "fixed",
        +        "byLevel",
        +        "spellSlot"
        +      ],
        +      "type": "string"
        +    },
        +    "scalingAttribute": {
        +      "type": "string"
        +    },
        +    "slotIncrement": {
        +      "additionalProperties": {},
        +      "properties": {
        +        "dice": {
        +          "type": "string"
        +        },
        +        "flat": {
        +          "type": "number"
        +        },
        +        "targets": {
        +          "maximum": 9007199254740991,
        +          "minimum": 1,
        +          "type": "integer"
        +        }
        +      },
        +      "type": "object"
        +    },
        +    "targets": {
        +      "additionalProperties": {},
        +      "properties": {
        +        "count": {
        +          "maximum": 9007199254740991,
        +          "minimum": 1,
        +          "type": "integer"
        +        }
        +      },
        +      "type": "object"
        +    },
        +    "trigger": {
        +      "enum": [
        +        "passive",
        +        "toggled",
        +        "reaction",
        +        "perRoll",
        +        "resource",
        +        "targetBound"
        +      ],
        +      "type": "string"
        +    },
        +    "types": {
        +      "items": {
        +        "type": "string"
        +      },
        +      "type": "array"
        +    }
        +  },
        +  "type": "object"
        +}
      • addedInput schema / properties / damageReduction
        Added value: +{
        +  "items": {
        +    "additionalProperties": {},
        +    "properties": {
        +      "amount": {
        +        "additionalProperties": {},
        +        "properties": {
        +          "dice": {
        +            "type": "string"
        +          },
        +          "flat": {
        +            "type": "number"
        +          },
        +          "includesProficiency": {
        +            "type": "boolean"
        +          },
        +          "modifierSource": {
        +            "enum": [
        +              "spellcasting",
        +              "attackAttribute",
        +              "strength",
        +              "dexterity",
        +              "constitution",
        +              "intelligence",
        +              "wisdom",
        +              "charisma"
        +            ],
        +            "type": "string"
        +          }
        +        },
        +        "type": "object"
        +      },
        +      "range": {
        +        "maximum": 9007199254740991,
        +        "minimum": 0,
        +        "type": "integer"
        +      },
        +      "requires": {
        +        "items": {
        +          "additionalProperties": {},
        +          "properties": {
        +            "armorCategories": {
        +              "description": "For 'equipped' + slot:armor: armor category list (Light / Medium / Heavy). OR semantics — match any.",
        +              "items": {
        +                "type": "string"
        +              },
        +              "type": "array"
        +            },
        +            "condition": {
        +              "description": "For 'condition' predicates: the character-state condition to gate on (5e24 named conditions and ongoing-action states).",
        +              "enum": [
        +                "blinded",
        +                "charmed",
        +                "dazed",
        +                "deafened",
        +                "exhaustion",
        +                "frightened",
        +                "grappled",
        +                "incapacitated",
        +                "invisible",
        +                "paralyzed",
        +                "petrified",
        +                "poisoned",
        +                "prone",
        +                "restrained",
        +                "stunned",
        +                "unconscious",
        +                "concentrating",
        +                "grappling",
        +                "dodging",
        +                "hiding",
        +                "raging"
        +              ],
        +              "type": "string"
        +            },
        +            "equipSlot": {
        +              "description": "Body slot the matched weapon must occupy. mainHand / offHand. Resolved via getRequiredSlots so two-handed grips occupy both.",
        +              "enum": [
        +                "mainHand",
        +                "offHand"
        +              ],
        +              "type": "string"
        +            },
        +            "negate": {
        +              "description": "true inverts the predicate — 'while NOT matching' instead of 'while matching'.",
        +              "type": "boolean"
        +            },
        +            "slot": {
        +              "description": "For 'equipped' predicates: the body category to match (armor / shield / weapon).",
        +              "enum": [
        +                "armor",
        +                "shield",
        +                "weapon"
        +              ],
        +              "type": "string"
        +            },
        +            "type": {
        +              "description": "Predicate type. 'equipped' = character-scoped (gates on what's equipped). 'attackingWeapon' = attack-scoped (gates on the current action's source weapon). 'condition' = gates on a character-state condition.",
        +              "enum": [
        +                "equipped",
        +                "attackingWeapon",
        +                "condition"
        +              ],
        +              "type": "string"
        +            },
        +            "weaponProperties": {
        +              "description": "For 'equipped' + slot:weapon OR 'attackingWeapon': weapon-property list. AND semantics — match all.",
        +              "items": {
        +                "type": "string"
        +              },
        +              "type": "array"
        +            }
        +          },
        +          "type": "object"
        +        },
        +        "type": "array"
        +      },
        +      "requiresLogic": {
        +        "enum": [
        +          "and",
        +          "or"
        +        ],
        +        "type": "string"
        +      },
        +      "target": {
        +        "enum": [
        +          "self",
        +          "ally",
        +          "any",
        +          "target",
        +          "enemy"
        +        ],
        +        "type": "string"
        +      },
        +      "trigger": {
        +        "enum": [
        +          "passive",
        +          "toggled",
        +          "reaction",
        +          "perRoll",
        +          "resource",
        +          "targetBound"
        +        ],
        +        "type": "string"
        +      },
        +      "types": {
        +        "items": {
        +          "type": "string"
        +        },
        +        "type": "array"
        +      }
        +    },
        +    "type": "object"
        +  },
        +  "type": "array"
        +}
      • addedInput schema / properties / defaultAbilityScores
        Added value: +{
        +  "additionalProperties": {},
        +  "properties": {
        +    "charisma": {
        +      "maximum": 30,
        +      "minimum": 1,
        +      "type": "integer"
        +    },
        +    "constitution": {
        +      "maximum": 30,
        +      "minimum": 1,
        +      "type": "integer"
        +    },
        +    "dexterity": {
        +      "maximum": 30,
        +      "minimum": 1,
        +      "type": "integer"
        +    },
        +    "intelligence": {
        +      "maximum": 30,
        +      "minimum": 1,
        +      "type": "integer"
        +    },
        +    "strength": {
        +      "maximum": 30,
        +      "minimum": 1,
        +      "type": "integer"
        +    },
        +    "wisdom": {
        +      "maximum": 30,
        +      "minimum": 1,
        +      "type": "integer"
        +    }
        +  },
        +  "type": "object"
        +}
      • addedInput schema / properties / description
        Added value: +{
        +  "description": "Full rule body. Markdown is supported.",
        +  "type": "string"
        +}
      • addedInput schema / properties / diceFloors
        Added value: +{
        +  "items": {
        +    "additionalProperties": {},
        +    "properties": {
        +      "appliesTo": {
        +        "enum": [
        +          "damage",
        +          "damage.melee",
        +          "damage.ranged",
        +          "damage.spell",
        +          "healing"
        +        ],
        +        "type": "string"
        +      },
        +      "floor": {
        +        "maximum": 9007199254740991,
        +        "minimum": 1,
        +        "type": "integer"
        +      },
        +      "requires": {
        +        "items": {
        +          "additionalProperties": {},
        +          "properties": {
        +            "armorCategories": {
        +              "description": "For 'equipped' + slot:armor: armor category list (Light / Medium / Heavy). OR semantics — match any.",
        +              "items": {
        +                "type": "string"
        +              },
        +              "type": "array"
        +            },
        +            "condition": {
        +              "description": "For 'condition' predicates: the character-state condition to gate on (5e24 named conditions and ongoing-action states).",
        +              "enum": [
        +                "blinded",
        +                "charmed",
        +                "dazed",
        +                "deafened",
        +                "exhaustion",
        +                "frightened",
        +                "grappled",
        +                "incapacitated",
        +                "invisible",
        +                "paralyzed",
        +                "petrified",
        +                "poisoned",
        +                "prone",
        +                "restrained",
        +                "stunned",
        +                "unconscious",
        +                "concentrating",
        +                "grappling",
        +                "dodging",
        +                "hiding",
        +                "raging"
        +              ],
        +              "type": "string"
        +            },
        +            "equipSlot": {
        +              "description": "Body slot the matched weapon must occupy. mainHand / offHand. Resolved via getRequiredSlots so two-handed grips occupy both.",
        +              "enum": [
        +                "mainHand",
        +                "offHand"
        +              ],
        +              "type": "string"
        +            },
        +            "negate": {
        +              "description": "true inverts the predicate — 'while NOT matching' instead of 'while matching'.",
        +              "type": "boolean"
        +            },
        +            "slot": {
        +              "description": "For 'equipped' predicates: the body category to match (armor / shield / weapon).",
        +              "enum": [
        +                "armor",
        +                "shield",
        +                "weapon"
        +              ],
        +              "type": "string"
        +            },
        +            "type": {
        +              "description": "Predicate type. 'equipped' = character-scoped (gates on what's equipped). 'attackingWeapon' = attack-scoped (gates on the current action's source weapon). 'condition' = gates on a character-state condition.",
        +              "enum": [
        +                "equipped",
        +                "attackingWeapon",
        +                "condition"
        +              ],
        +              "type": "string"
        +            },
        +            "weaponProperties": {
        +              "description": "For 'equipped' + slot:weapon OR 'attackingWeapon': weapon-property list. AND semantics — match all.",
        +              "items": {
        +                "type": "string"
        +              },
        +              "type": "array"
        +            }
        +          },
        +          "type": "object"
        +        },
        +        "type": "array"
        +      },
        +      "requiresLogic": {
        +        "enum": [
        +          "and",
        +          "or"
        +        ],
        +        "type": "string"
        +      },
        +      "threshold": {
        +        "maximum": 9007199254740991,
        +        "minimum": 1,
        +        "type": "integer"
        +      },
        +      "trigger": {
        +        "enum": [
        +          "passive",
        +          "toggled",
        +          "reaction",
        +          "perRoll",
        +          "resource",
        +          "targetBound"
        +        ],
        +        "type": "string"
        +      }
        +    },
        +    "type": "object"
        +  },
        +  "type": "array"
        +}
      • addedInput schema / properties / diceReplacements
        Added value: +{
        +  "items": {
        +    "additionalProperties": {},
        +    "properties": {
        +      "_target": {
        +        "description": "Mongo `_id` reference (24-character hex string).",
        +        "minLength": 1,
        +        "type": "string"
        +      },
        +      "dice": {
        +        "type": "string"
        +      },
        +      "progression": {
        +        "items": {
        +          "additionalProperties": {},
        +          "properties": {
        +            "dice": {
        +              "type": "string"
        +            },
        +            "level": {
        +              "maximum": 20,
        +              "minimum": 1,
        +              "type": "integer"
        +            }
        +          },
        +          "type": "object"
        +        },
        +        "type": "array"
        +      },
        +      "requires": {
        +        "items": {
        +          "additionalProperties": {},
        +          "properties": {
        +            "armorCategories": {
        +              "description": "For 'equipped' + slot:armor: armor category list (Light / Medium / Heavy). OR semantics — match any.",
        +              "items": {
        +                "type": "string"
        +              },
        +              "type": "array"
        +            },
        +            "condition": {
        +              "description": "For 'condition' predicates: the character-state condition to gate on (5e24 named conditions and ongoing-action states).",
        +              "enum": [
        +                "blinded",
        +                "charmed",
        +                "dazed",
        +                "deafened",
        +                "exhaustion",
        +                "frightened",
        +                "grappled",
        +                "incapacitated",
        +                "invisible",
        +                "paralyzed",
        +                "petrified",
        +                "poisoned",
        +                "prone",
        +                "restrained",
        +                "stunned",
        +                "unconscious",
        +                "concentrating",
        +                "grappling",
        +                "dodging",
        +                "hiding",
        +                "raging"
        +              ],
        +              "type": "string"
        +            },
        +            "equipSlot": {
        +              "description": "Body slot the matched weapon must occupy. mainHand / offHand. Resolved via getRequiredSlots so two-handed grips occupy both.",
        +              "enum": [
        +                "mainHand",
        +                "offHand"
        +              ],
        +              "type": "string"
        +            },
        +            "negate": {
        +              "description": "true inverts the predicate — 'while NOT matching' instead of 'while matching'.",
        +              "type": "boolean"
        +            },
        +            "slot": {
        +              "description": "For 'equipped' predicates: the body category to match (armor / shield / weapon).",
        +              "enum": [
        +                "armor",
        +                "shield",
        +                "weapon"
        +              ],
        +              "type": "string"
        +            },
        +            "type": {
        +              "description": "Predicate type. 'equipped' = character-scoped (gates on what's equipped). 'attackingWeapon' = attack-scoped (gates on the current action's source weapon). 'condition' = gates on a character-state condition.",
        +              "enum": [
        +                "equipped",
        +                "attackingWeapon",
        +                "condition"
        +              ],
        +              "type": "string"
        +            },
        +            "weaponProperties": {
        +              "description": "For 'equipped' + slot:weapon OR 'attackingWeapon': weapon-property list. AND semantics — match all.",
        +              "items": {
        +                "type": "string"
        +              },
        +              "type": "array"
        +            }
        +          },
        +          "type": "object"
        +        },
        +        "type": "array"
        +      },
        +      "requiresLogic": {
        +        "enum": [
        +          "and",
        +          "or"
        +        ],
        +        "type": "string"
        +      }
        +    },
        +    "type": "object"
        +  },
        +  "type": "array"
        +}
      • addedInput schema / properties / duration
        Added value: +{
        +  "additionalProperties": {},
        +  "properties": {
        +    "concentration": {
        +      "type": "boolean"
        +    },
        +    "count": {
        +      "maximum": 9007199254740991,
        +      "minimum": 0,
        +      "type": "integer"
        +    },
        +    "unit": {
        +      "enum": [
        +        "round",
        +        "minute",
        +        "hour",
        +        "day",
        +        "untilShortRest",
        +        "untilLongRest",
        +        "special"
        +      ],
        +      "type": "string"
        +    }
        +  },
        +  "type": "object"
        +}
      • addedInput schema / properties / effect
        Added value: +{
        +  "additionalProperties": {},
        +  "properties": {
        +    "audience": {
        +      "enum": [
        +        "self",
        +        "ally",
        +        "any",
        +        "target",
        +        "enemy"
        +      ],
        +      "type": "string"
        +    },
        +    "conditions": {
        +      "items": {
        +        "additionalProperties": {},
        +        "properties": {
        +          "applyWhen": {
        +            "enum": [
        +              "always",
        +              "onFail",
        +              "onSuccess"
        +            ],
        +            "type": "string"
        +          },
        +          "durationCount": {
        +            "maximum": 9007199254740991,
        +            "minimum": 0,
        +            "type": "integer"
        +          },
        +          "durationUnit": {
        +            "enum": [
        +              "round",
        +              "minute",
        +              "hour",
        +              "day",
        +              "untilShortRest",
        +              "untilLongRest",
        +              "special"
        +            ],
        +            "type": "string"
        +          },
        +          "name": {
        +            "type": "string"
        +          },
        +          "target": {
        +            "enum": [
        +              "self",
        +              "target"
        +            ],
        +            "type": "string"
        +          }
        +        },
        +        "type": "object"
        +      },
        +      "type": "array"
        +    },
        +    "save": {
        +      "additionalProperties": {},
        +      "properties": {
        +        "ability": {
        +          "enum": [
        +            "none",
        +            "spellcasting",
        +            "attackAttribute",
        +            "strength",
        +            "dexterity",
        +            "constitution",
        +            "intelligence",
        +            "wisdom",
        +            "charisma"
        +          ],
        +          "type": "string"
        +        },
        +        "dcBase": {
        +          "type": "number"
        +        },
        +        "includesProficiency": {
        +          "type": "boolean"
        +        },
        +        "saveType": {
        +          "enum": [
        +            "strength",
        +            "dexterity",
        +            "constitution",
        +            "intelligence",
        +            "wisdom",
        +            "charisma"
        +          ],
        +          "type": "string"
        +        }
        +      },
        +      "type": "object"
        +    },
        +    "triggerEvent": {
        +      "enum": [
        +        "onHit",
        +        "onMiss",
        +        "onDamage",
        +        "startOfYourTurn",
        +        "endOfYourTurn",
        +        "startOfTargetTurn",
        +        "endOfTargetTurn"
        +      ],
        +      "type": "string"
        +    }
        +  },
        +  "type": "object"
        +}
      • addedInput schema / properties / feat
        Added value: +{
        +  "description": "Mongo `_id` reference (24-character hex string).",
        +  "minLength": 1,
        +  "type": "string"
        +}
      • addedInput schema / properties / featOpen
        Added value: +{
        +  "type": "boolean"
        +}
      • addedInput schema / properties / forcedMovement
        Added value: +{
        +  "items": {
        +    "additionalProperties": {},
        +    "properties": {
        +      "audience": {
        +        "enum": [
        +          "self",
        +          "ally",
        +          "any",
        +          "target",
        +          "enemy"
        +        ],
        +        "type": "string"
        +      },
        +      "direction": {
        +        "enum": [
        +          "awayFromSelf",
        +          "towardSelf",
        +          "anywhere"
        +        ],
        +        "type": "string"
        +      },
        +      "distance": {
        +        "maximum": 9007199254740991,
        +        "minimum": 0,
        +        "type": "integer"
        +      },
        +      "maxTargetSize": {
        +        "enum": [
        +          "tiny",
        +          "small",
        +          "medium",
        +          "large",
        +          "huge",
        +          "gargantuan"
        +        ],
        +        "type": "string"
        +      },
        +      "requires": {
        +        "items": {
        +          "additionalProperties": {},
        +          "properties": {
        +            "armorCategories": {
        +              "description": "For 'equipped' + slot:armor: armor category list (Light / Medium / Heavy). OR semantics — match any.",
        +              "items": {
        +                "type": "string"
        +              },
        +              "type": "array"
        +            },
        +            "condition": {
        +              "description": "For 'condition' predicates: the character-state condition to gate on (5e24 named conditions and ongoing-action states).",
        +              "enum": [
        +                "blinded",
        +                "charmed",
        +                "dazed",
        +                "deafened",
        +                "exhaustion",
        +                "frightened",
        +                "grappled",
        +                "incapacitated",
        +                "invisible",
        +                "paralyzed",
        +                "petrified",
        +                "poisoned",
        +                "prone",
        +                "restrained",
        +                "stunned",
        +                "unconscious",
        +                "concentrating",
        +                "grappling",
        +                "dodging",
        +                "hiding",
        +                "raging"
        +              ],
        +              "type": "string"
        +            },
        +            "equipSlot": {
        +              "description": "Body slot the matched weapon must occupy. mainHand / offHand. Resolved via getRequiredSlots so two-handed grips occupy both.",
        +              "enum": [
        +                "mainHand",
        +                "offHand"
        +              ],
        +              "type": "string"
        +            },
        +            "negate": {
        +              "description": "true inverts the predicate — 'while NOT matching' instead of 'while matching'.",
        +              "type": "boolean"
        +            },
        +            "slot": {
        +              "description": "For 'equipped' predicates: the body category to match (armor / shield / weapon).",
        +              "enum": [
        +                "armor",
        +                "shield",
        +                "weapon"
        +              ],
        +              "type": "string"
        +            },
        +            "type": {
        +              "description": "Predicate type. 'equipped' = character-scoped (gates on what's equipped). 'attackingWeapon' = attack-scoped (gates on the current action's source weapon). 'condition' = gates on a character-state condition.",
        +              "enum": [
        +                "equipped",
        +                "attackingWeapon",
        +                "condition"
        +              ],
        +              "type": "string"
        +            },
        +            "weaponProperties": {
        +              "description": "For 'equipped' + slot:weapon OR 'attackingWeapon': weapon-property list. AND semantics — match all.",
        +              "items": {
        +                "type": "string"
        +              },
        +              "type": "array"
        +            }
        +          },
        +          "type": "object"
        +        },
        +        "type": "array"
        +      },
        +      "requiresLogic": {
        +        "enum": [
        +          "and",
        +          "or"
        +        ],
        +        "type": "string"
        +      },
        +      "triggerEvent": {
        +        "enum": [
        +          "onHit",
        +          "onMiss",
        +          "onDamage",
        +          "startOfYourTurn",
        +          "endOfYourTurn",
        +          "startOfTargetTurn",
        +          "endOfTargetTurn"
        +        ],
        +        "type": "string"
        +      }
        +    },
        +    "type": "object"
        +  },
        +  "type": "array"
        +}
      • addedInput schema / properties / healing
        Added value: +{
        +  "additionalProperties": {},
        +  "properties": {
        +    "dice": {
        +      "type": "string"
        +    },
        +    "flat": {
        +      "type": "number"
        +    },
        +    "modifierSource": {
        +      "enum": [
        +        "level",
        +        "spellcasting",
        +        "strength",
        +        "dexterity",
        +        "constitution",
        +        "intelligence",
        +        "wisdom",
        +        "charisma"
        +      ],
        +      "type": "string"
        +    },
        +    "progression": {
        +      "items": {
        +        "additionalProperties": {},
        +        "properties": {
        +          "dice": {
        +            "type": "string"
        +          },
        +          "flat": {
        +            "type": "number"
        +          },
        +          "level": {
        +            "maximum": 20,
        +            "minimum": 1,
        +            "type": "integer"
        +          }
        +        },
        +        "type": "object"
        +      },
        +      "type": "array"
        +    },
        +    "scaling": {
        +      "enum": [
        +        "fixed",
        +        "byLevel",
        +        "proficiency",
        +        "spellSlot"
        +      ],
        +      "type": "string"
        +    },
        +    "slotIncrement": {
        +      "additionalProperties": {},
        +      "properties": {
        +        "dice": {
        +          "type": "string"
        +        },
        +        "flat": {
        +          "type": "number"
        +        }
        +      },
        +      "type": "object"
        +    },
        +    "target": {
        +      "enum": [
        +        "self",
        +        "ally",
        +        "any",
        +        "multiple"
        +      ],
        +      "type": "string"
        +    },
        +    "targets": {
        +      "additionalProperties": {},
        +      "properties": {
        +        "count": {
        +          "maximum": 9007199254740991,
        +          "minimum": 1,
        +          "type": "integer"
        +        }
        +      },
        +      "type": "object"
        +    }
        +  },
        +  "type": "object"
        +}
      • addedInput schema / properties / hitDie
        Added value: +{
        +  "type": "string"
        +}
      • addedInput schema / properties / id
        Added value: +{
        +  "description": "Mongo `_id` of the rule to update.",
        +  "minLength": 1,
        +  "type": "string"
        +}
      • addedInput schema / properties / image
        Added value: +{
        +  "additionalProperties": {},
        +  "properties": {
        +    "url": {
        +      "description": "Image URL hosted on Embers Images (or any addressable HTTPS URL).",
        +      "type": "string"
        +    }
        +  },
        +  "type": "object"
        +}
      • addedInput schema / properties / keywords
        Added value: +{
        +  "items": {
        +    "type": "string"
        +  },
        +  "type": "array"
        +}
      • addedInput schema / properties / languages
        Added value: +{
        +  "additionalProperties": {},
        +  "properties": {
        +    "choose": {
        +      "additionalProperties": {},
        +      "properties": {
        +        "count": {
        +          "maximum": 9007199254740991,
        +          "minimum": 0,
        +          "type": "integer"
        +        },
        +        "options": {
        +          "items": {
        +            "type": "string"
        +          },
        +          "type": "array"
        +        }
        +      },
        +      "type": "object"
        +    },
        +    "fixed": {
        +      "items": {
        +        "type": "string"
        +      },
        +      "type": "array"
        +    }
        +  },
        +  "type": "object"
        +}
      • addedInput schema / properties / levelProgression
        Added value: +{
        +  "items": {
        +    "additionalProperties": {},
        +    "properties": {
        +      "name": {
        +        "type": "string"
        +      },
        +      "values": {
        +        "items": {
        +          "type": "string"
        +        },
        +        "type": "array"
        +      }
        +    },
        +    "type": "object"
        +  },
        +  "type": "array"
        +}
      • addedInput schema / properties / mechanicsKey
        Added value: +{
        +  "type": "string"
        +}
      • addedInput schema / properties / multiclassing
        Added value: +{
        +  "additionalProperties": {},
        +  "description": "What multiclassing INTO this class grants (weapon/armor lists apply fixed; skillChoices/toolChoices render pickers). Absent = no multiclass proficiencies.",
        +  "properties": {
        +    "armorTraining": {
        +      "items": {
        +        "type": "string"
        +      },
        +      "type": "array"
        +    },
        +    "skillChoices": {
        +      "additionalProperties": {},
        +      "properties": {
        +        "count": {
        +          "maximum": 9007199254740991,
        +          "minimum": 0,
        +          "type": "integer"
        +        },
        +        "options": {
        +          "items": {
        +            "type": "string"
        +          },
        +          "type": "array"
        +        }
        +      },
        +      "type": "object"
        +    },
        +    "toolChoices": {
        +      "additionalProperties": {},
        +      "properties": {
        +        "count": {
        +          "maximum": 9007199254740991,
        +          "minimum": 0,
        +          "type": "integer"
        +        },
        +        "options": {
        +          "items": {
        +            "type": "string"
        +          },
        +          "type": "array"
        +        }
        +      },
        +      "type": "object"
        +    },
        +    "toolProficiencies": {
        +      "items": {
        +        "type": "string"
        +      },
        +      "type": "array"
        +    },
        +    "weaponProficiencies": {
        +      "items": {
        +        "type": "string"
        +      },
        +      "type": "array"
        +    }
        +  },
        +  "type": "object"
        +}
      • addedInput schema / properties / name
        Added value: +{
        +  "description": "Display name of the rule.",
        +  "minLength": 1,
        +  "type": "string"
        +}
      • addedInput schema / properties / ogl
        Added value: +{
        +  "type": "boolean"
        +}
      • addedInput schema / properties / parameters
        Added value: +{
        +  "items": {
        +    "additionalProperties": {},
        +    "properties": {
        +      "label": {
        +        "type": "string"
        +      },
        +      "max": {
        +        "type": "number"
        +      },
        +      "min": {
        +        "type": "number"
        +      },
        +      "name": {
        +        "type": "string"
        +      },
        +      "type": {
        +        "enum": [
        +          "number",
        +          "string",
        +          "enum"
        +        ],
        +        "type": "string"
        +      },
        +      "unit": {
        +        "type": "string"
        +      }
        +    },
        +    "type": "object"
        +  },
        +  "type": "array"
        +}
      • addedInput schema / properties / preparedSpells
        Added value: +{
        +  "additionalProperties": {},
        +  "properties": {
        +    "count": {
        +      "maximum": 9007199254740991,
        +      "minimum": 0,
        +      "type": "integer"
        +    },
        +    "progression": {
        +      "items": {
        +        "additionalProperties": {},
        +        "properties": {
        +          "count": {
        +            "maximum": 9007199254740991,
        +            "minimum": 0,
        +            "type": "integer"
        +          },
        +          "level": {
        +            "maximum": 20,
        +            "minimum": 1,
        +            "type": "integer"
        +          }
        +        },
        +        "type": "object"
        +      },
        +      "type": "array"
        +    }
        +  },
        +  "type": "object"
        +}
      • addedInput schema / properties / prerequisites
        Added value: +{
        +  "items": {
        +    "additionalProperties": {},
        +    "properties": {
        +      "abilities": {
        +        "description": "For abilityScore: ANY listed ability meeting `min` satisfies ('Str or Dex 13+').",
        +        "items": {
        +          "enum": [
        +            "strength",
        +            "dexterity",
        +            "constitution",
        +            "intelligence",
        +            "wisdom",
        +            "charisma"
        +          ],
        +          "type": "string"
        +        },
        +        "type": "array"
        +      },
        +      "category": {
        +        "description": "For rule (filter): matches any held rule in this category.",
        +        "type": "string"
        +      },
        +      "class": {
        +        "description": "For a `level` predicate: a Class rule id that scopes `min` to 'Nth level in that class'. Absent = total character level.",
        +        "minLength": 1,
        +        "type": "string"
        +      },
        +      "min": {
        +        "description": "Numeric minimum — character level (level), class level (class), or ability score (abilityScore).",
        +        "maximum": 9007199254740991,
        +        "minimum": 0,
        +        "type": "integer"
        +      },
        +      "negate": {
        +        "description": "true inverts the predicate — 'must NOT meet this'.",
        +        "type": "boolean"
        +      },
        +      "proficiency": {
        +        "description": "For proficiency: the proficiency name (e.g. 'Martial', 'Stealth').",
        +        "type": "string"
        +      },
        +      "proficiencyType": {
        +        "description": "For proficiency: the family.",
        +        "enum": [
        +          "skill",
        +          "tool",
        +          "weapon",
        +          "armor",
        +          "save",
        +          "language"
        +        ],
        +        "type": "string"
        +      },
        +      "rule": {
        +        "description": "For rule: a specific held Rule id.",
        +        "minLength": 1,
        +        "type": "string"
        +      },
        +      "ruleType": {
        +        "description": "For rule (filter): matches any held rule of this type.",
        +        "type": "string"
        +      },
        +      "spell": {
        +        "description": "For spell: a specific known Spell id.",
        +        "minLength": 1,
        +        "type": "string"
        +      },
        +      "spellList": {
        +        "description": "For spell (filter): knows any spell from this class list.",
        +        "type": "string"
        +      },
        +      "type": {
        +        "description": "Predicate kind: level / abilityScore / rule / spell / proficiency / spellcasting. (A class is required via a `rule` predicate pointing at the class rule.)",
        +        "enum": [
        +          "level",
        +          "abilityScore",
        +          "rule",
        +          "spell",
        +          "proficiency",
        +          "spellcasting"
        +        ],
        +        "type": "string"
        +      }
        +    },
        +    "type": "object"
        +  },
        +  "type": "array"
        +}
      • addedInput schema / properties / prerequisitesLogic
        Added value: +{
        +  "enum": [
        +    "and",
        +    "or"
        +  ],
        +  "type": "string"
        +}
      • addedInput schema / properties / proficiencyChoices
        Added value: +{
        +  "items": {
        +    "additionalProperties": {},
        +    "properties": {
        +      "allowedItems": {
        +        "items": {
        +          "type": "string"
        +        },
        +        "type": "array"
        +      },
        +      "level": {
        +        "enum": [
        +          "proficient",
        +          "expertise"
        +        ],
        +        "type": "string"
        +      },
        +      "mode": {
        +        "enum": [
        +          "specific",
        +          "all"
        +        ],
        +        "type": "string"
        +      },
        +      "progression": {
        +        "items": {
        +          "additionalProperties": {},
        +          "properties": {
        +            "count": {
        +              "maximum": 9007199254740991,
        +              "minimum": 0,
        +              "type": "integer"
        +            },
        +            "level": {
        +              "maximum": 20,
        +              "minimum": 1,
        +              "type": "integer"
        +            }
        +          },
        +          "type": "object"
        +        },
        +        "type": "array"
        +      },
        +      "types": {
        +        "items": {
        +          "enum": [
        +            "skill",
        +            "tool",
        +            "save",
        +            "weapon",
        +            "armor",
        +            "language"
        +          ],
        +          "type": "string"
        +        },
        +        "type": "array"
        +      }
        +    },
        +    "type": "object"
        +  },
        +  "type": "array"
        +}
      • addedInput schema / properties / publisher
        Added value: +{
        +  "type": "string"
        +}
      • addedInput schema / properties / range
        Added value: +{
        +  "additionalProperties": {},
        +  "description": "How far the ability reaches when invoked — self, touch, or ranged with a distance ('feet' default, 'miles' for long reaches). Absent = runtime defaults (self-heals on the user, targeted abilities at touch).",
        +  "properties": {
        +    "distance": {
        +      "minimum": 0,
        +      "type": "number"
        +    },
        +    "kind": {
        +      "enum": [
        +        "self",
        +        "touch",
        +        "ranged",
        +        "sight",
        +        "unlimited",
        +        "special"
        +      ],
        +      "type": "string"
        +    },
        +    "unit": {
        +      "enum": [
        +        "feet",
        +        "miles"
        +      ],
        +      "type": "string"
        +    }
        +  },
        +  "type": "object"
        +}
      • addedInput schema / properties / recurringDamage
        Added value: +{
        +  "items": {
        +    "additionalProperties": {},
        +    "properties": {
        +      "amount": {
        +        "additionalProperties": {},
        +        "properties": {
        +          "dice": {
        +            "type": "string"
        +          },
        +          "flat": {
        +            "type": "number"
        +          },
        +          "includesProficiency": {
        +            "type": "boolean"
        +          },
        +          "modifierSource": {
        +            "enum": [
        +              "spellcasting",
        +              "attackAttribute",
        +              "strength",
        +              "dexterity",
        +              "constitution",
        +              "intelligence",
        +              "wisdom",
        +              "charisma"
        +            ],
        +            "type": "string"
        +          }
        +        },
        +        "type": "object"
        +      },
        +      "audience": {
        +        "enum": [
        +          "self",
        +          "ally",
        +          "any",
        +          "target",
        +          "enemy"
        +        ],
        +        "type": "string"
        +      },
        +      "durationCount": {
        +        "maximum": 9007199254740991,
        +        "minimum": 0,
        +        "type": "integer"
        +      },
        +      "durationUnit": {
        +        "enum": [
        +          "instantaneous",
        +          "untilStartOfNextTurn",
        +          "untilEndOfNextTurn",
        +          "round",
        +          "minute",
        +          "hour",
        +          "untilShortRest",
        +          "untilLongRest"
        +        ],
        +        "type": "string"
        +      },
        +      "ignoreResistances": {
        +        "type": "boolean"
        +      },
        +      "inheritDamageType": {
        +        "type": "boolean"
        +      },
        +      "range": {
        +        "maximum": 9007199254740991,
        +        "minimum": 0,
        +        "type": "integer"
        +      },
        +      "requires": {
        +        "items": {
        +          "additionalProperties": {},
        +          "properties": {
        +            "armorCategories": {
        +              "description": "For 'equipped' + slot:armor: armor category list (Light / Medium / Heavy). OR semantics — match any.",
        +              "items": {
        +                "type": "string"
        +              },
        +              "type": "array"
        +            },
        +            "condition": {
        +              "description": "For 'condition' predicates: the character-state condition to gate on (5e24 named conditions and ongoing-action states).",
        +              "enum": [
        +                "blinded",
        +                "charmed",
        +                "dazed",
        +                "deafened",
        +                "exhaustion",
        +                "frightened",
        +                "grappled",
        +                "incapacitated",
        +                "invisible",
        +                "paralyzed",
        +                "petrified",
        +                "poisoned",
        +                "prone",
        +                "restrained",
        +                "stunned",
        +                "unconscious",
        +                "concentrating",
        +                "grappling",
        +                "dodging",
        +                "hiding",
        +                "raging"
        +              ],
        +              "type": "string"
        +            },
        +            "equipSlot": {
        +              "description": "Body slot the matched weapon must occupy. mainHand / offHand. Resolved via getRequiredSlots so two-handed grips occupy both.",
        +              "enum": [
        +                "mainHand",
        +                "offHand"
        +              ],
        +              "type": "string"
        +            },
        +            "negate": {
        +              "description": "true inverts the predicate — 'while NOT matching' instead of 'while matching'.",
        +              "type": "boolean"
        +            },
        +            "slot": {
        +              "description": "For 'equipped' predicates: the body category to match (armor / shield / weapon).",
        +              "enum": [
        +                "armor",
        +                "shield",
        +                "weapon"
        +              ],
        +              "type": "string"
        +            },
        +            "type": {
        +              "description": "Predicate type. 'equipped' = character-scoped (gates on what's equipped). 'attackingWeapon' = attack-scoped (gates on the current action's source weapon). 'condition' = gates on a character-state condition.",
        +              "enum": [
        +                "equipped",
        +                "attackingWeapon",
        +                "condition"
        +              ],
        +              "type": "string"
        +            },
        +            "weaponProperties": {
        +              "description": "For 'equipped' + slot:weapon OR 'attackingWeapon': weapon-property list. AND semantics — match all.",
        +              "items": {
        +                "type": "string"
        +              },
        +              "type": "array"
        +            }
        +          },
        +          "type": "object"
        +        },
        +        "type": "array"
        +      },
        +      "requiresLogic": {
        +        "enum": [
        +          "and",
        +          "or"
        +        ],
        +        "type": "string"
        +      },
        +      "triggerEvent": {
        +        "enum": [
        +          "startOfYourTurn",
        +          "endOfYourTurn",
        +          "startOfTargetTurn",
        +          "endOfTargetTurn",
        +          "whenTargetEntersArea",
        +          "onHit",
        +          "onMiss",
        +          "onDamage"
        +        ],
        +        "type": "string"
        +      },
        +      "types": {
        +        "items": {
        +          "type": "string"
        +        },
        +        "type": "array"
        +      }
        +    },
        +    "type": "object"
        +  },
        +  "type": "array"
        +}
      • addedInput schema / properties / repeatable
        Added value: +{
        +  "description": "A rule that may be taken/granted more than once, each time as a distinct instance with its own sub-choices — a repeatable Feat (Skilled, Resilient), or a class's Ability Score Improvement ability, which its class grants at several levels.",
        +  "type": "boolean"
        +}
      • addedInput schema / properties / resistances
        Added value: +{
        +  "items": {
        +    "additionalProperties": {},
        +    "properties": {
        +      "mode": {
        +        "enum": [
        +          "resistance",
        +          "immunity",
        +          "vulnerability"
        +        ],
        +        "type": "string"
        +      },
        +      "range": {
        +        "description": "Aura radius in feet for ally/any-targeted resistances (Warding Aura's 10 ft.). Absent = self-only.",
        +        "maximum": 9007199254740991,
        +        "minimum": 0,
        +        "type": "integer"
        +      },
        +      "target": {
        +        "description": "Who the resistance protects — mirrors damageReduction's target/range pair. Absent = self.",
        +        "enum": [
        +          "self",
        +          "ally",
        +          "any",
        +          "target",
        +          "enemy"
        +        ],
        +        "type": "string"
        +      },
        +      "trigger": {
        +        "enum": [
        +          "passive",
        +          "toggled",
        +          "reaction",
        +          "perRoll",
        +          "resource",
        +          "targetBound"
        +        ],
        +        "type": "string"
        +      },
        +      "types": {
        +        "items": {
        +          "type": "string"
        +        },
        +        "type": "array"
        +      }
        +    },
        +    "type": "object"
        +  },
        +  "type": "array"
        +}
      • addedInput schema / properties / rollMods
        Added value: +{
        +  "items": {
        +    "additionalProperties": {},
        +    "properties": {
        +      "audience": {
        +        "enum": [
        +          "self",
        +          "ally",
        +          "any",
        +          "target",
        +          "enemy"
        +        ],
        +        "type": "string"
        +      },
        +      "consumeOnUse": {
        +        "type": "boolean"
        +      },
        +      "durationCount": {
        +        "maximum": 9007199254740991,
        +        "minimum": 0,
        +        "type": "integer"
        +      },
        +      "durationUnit": {
        +        "enum": [
        +          "instantaneous",
        +          "untilStartOfNextTurn",
        +          "untilEndOfNextTurn",
        +          "round",
        +          "minute",
        +          "hour",
        +          "untilShortRest",
        +          "untilLongRest"
        +        ],
        +        "type": "string"
        +      },
        +      "mode": {
        +        "enum": [
        +          "advantage",
        +          "disadvantage"
        +        ],
        +        "type": "string"
        +      },
        +      "range": {
        +        "maximum": 9007199254740991,
        +        "minimum": 0,
        +        "type": "integer"
        +      },
        +      "requires": {
        +        "items": {
        +          "additionalProperties": {},
        +          "properties": {
        +            "armorCategories": {
        +              "description": "For 'equipped' + slot:armor: armor category list (Light / Medium / Heavy). OR semantics — match any.",
        +              "items": {
        +                "type": "string"
        +              },
        +              "type": "array"
        +            },
        +            "condition": {
        +              "description": "For 'condition' predicates: the character-state condition to gate on (5e24 named conditions and ongoing-action states).",
        +              "enum": [
        +                "blinded",
        +                "charmed",
        +                "dazed",
        +                "deafened",
        +                "exhaustion",
        +                "frightened",
        +                "grappled",
        +                "incapacitated",
        +                "invisible",
        +                "paralyzed",
        +                "petrified",
        +                "poisoned",
        +                "prone",
        +                "restrained",
        +                "stunned",
        +                "unconscious",
        +                "concentrating",
        +                "grappling",
        +                "dodging",
        +                "hiding",
        +                "raging"
        +              ],
        +              "type": "string"
        +            },
        +            "equipSlot": {
        +              "description": "Body slot the matched weapon must occupy. mainHand / offHand. Resolved via getRequiredSlots so two-handed grips occupy both.",
        +              "enum": [
        +                "mainHand",
        +                "offHand"
        +              ],
        +              "type": "string"
        +            },
        +            "negate": {
        +              "description": "true inverts the predicate — 'while NOT matching' instead of 'while matching'.",
        +              "type": "boolean"
        +            },
        +            "slot": {
        +              "description": "For 'equipped' predicates: the body category to match (armor / shield / weapon).",
        +              "enum": [
        +                "armor",
        +                "shield",
        +                "weapon"
        +              ],
        +              "type": "string"
        +            },
        +            "type": {
        +              "description": "Predicate type. 'equipped' = character-scoped (gates on what's equipped). 'attackingWeapon' = attack-scoped (gates on the current action's source weapon). 'condition' = gates on a character-state condition.",
        +              "enum": [
        +                "equipped",
        +                "attackingWeapon",
        +                "condition"
        +              ],
        +              "type": "string"
        +            },
        +            "weaponProperties": {
        +              "description": "For 'equipped' + slot:weapon OR 'attackingWeapon': weapon-property list. AND semantics — match all.",
        +              "items": {
        +                "type": "string"
        +              },
        +              "type": "array"
        +            }
        +          },
        +          "type": "object"
        +        },
        +        "type": "array"
        +      },
        +      "requiresLogic": {
        +        "enum": [
        +          "and",
        +          "or"
        +        ],
        +        "type": "string"
        +      },
        +      "rollScope": {
        +        "enum": [
        +          "attack",
        +          "save",
        +          "abilityCheck",
        +          "skillCheck"
        +        ],
        +        "type": "string"
        +      },
        +      "trigger": {
        +        "enum": [
        +          "passive",
        +          "toggled",
        +          "reaction",
        +          "perRoll",
        +          "resource",
        +          "targetBound"
        +        ],
        +        "type": "string"
        +      },
        +      "triggerEvent": {
        +        "enum": [
        +          "onHit",
        +          "onMiss",
        +          "onDamage",
        +          "startOfYourTurn",
        +          "endOfYourTurn",
        +          "startOfTargetTurn",
        +          "endOfTargetTurn"
        +        ],
        +        "type": "string"
        +      }
        +    },
        +    "type": "object"
        +  },
        +  "type": "array"
        +}
      • addedInput schema / properties / ruleChoice
        Added value: +{
        +  "additionalProperties": {},
        +  "properties": {
        +    "allowedCategories": {
        +      "items": {
        +        "type": "string"
        +      },
        +      "type": "array"
        +    },
        +    "allowedRuleParameters": {
        +      "additionalProperties": {
        +        "additionalProperties": {},
        +        "properties": {
        +          "damageType": {
        +            "type": "string"
        +          },
        +          "number": {
        +            "maximum": 9007199254740991,
        +            "minimum": 0,
        +            "type": "integer"
        +          },
        +          "range": {
        +            "maximum": 9007199254740991,
        +            "minimum": 0,
        +            "type": "integer"
        +          },
        +          "speed": {
        +            "maximum": 9007199254740991,
        +            "minimum": 0,
        +            "type": "integer"
        +          }
        +        },
        +        "type": "object"
        +      },
        +      "propertyNames": {
        +        "type": "string"
        +      },
        +      "type": "object"
        +    },
        +    "allowedRules": {
        +      "items": {
        +        "description": "Mongo `_id` reference (24-character hex string).",
        +        "minLength": 1,
        +        "type": "string"
        +      },
        +      "type": "array"
        +    },
        +    "allowedTypes": {
        +      "items": {
        +        "type": "string"
        +      },
        +      "type": "array"
        +    },
        +    "count": {
        +      "maximum": 9007199254740991,
        +      "minimum": 0,
        +      "type": "integer"
        +    },
        +    "label": {
        +      "type": "string"
        +    },
        +    "mode": {
        +      "enum": [
        +        "filter",
        +        "specific"
        +      ],
        +      "type": "string"
        +    },
        +    "progression": {
        +      "items": {
        +        "additionalProperties": {},
        +        "properties": {
        +          "count": {
        +            "maximum": 9007199254740991,
        +            "minimum": 0,
        +            "type": "integer"
        +          },
        +          "level": {
        +            "maximum": 20,
        +            "minimum": 1,
        +            "type": "integer"
        +          }
        +        },
        +        "type": "object"
        +      },
        +      "type": "array"
        +    },
        +    "scaling": {
        +      "enum": [
        +        "fixed",
        +        "byLevel"
        +      ],
        +      "type": "string"
        +    }
        +  },
        +  "type": "object"
        +}
      • addedInput schema / properties / ruleset
        Added value: +{
        +  "description": "Ruleset code (e.g. '5th Edition', '5e24', 'PFRPG', 'Savage Worlds', 'Universal').",
        +  "type": "string"
        +}
      • addedInput schema / properties / savingThrows
        Added value: +{
        +  "items": {
        +    "type": "string"
        +  },
        +  "type": "array"
        +}
      • addedInput schema / properties / size
        Added value: +{
        +  "items": {
        +    "type": "string"
        +  },
        +  "type": "array"
        +}
      • addedInput schema / properties / skillChoices
        Added value: +{
        +  "additionalProperties": {},
        +  "properties": {
        +    "count": {
        +      "maximum": 9007199254740991,
        +      "minimum": 0,
        +      "type": "integer"
        +    },
        +    "options": {
        +      "items": {
        +        "type": "string"
        +      },
        +      "type": "array"
        +    }
        +  },
        +  "type": "object"
        +}
      • addedInput schema / properties / skillProficiencies
        Added value: +{
        +  "items": {
        +    "type": "string"
        +  },
        +  "type": "array"
        +}
      • addedInput schema / properties / source
        Added value: +{
        +  "type": "string"
        +}
      • addedInput schema / properties / speed
        Added value: +{
        +  "maximum": 9007199254740991,
        +  "minimum": 0,
        +  "type": "integer"
        +}
      • addedInput schema / properties / spellAbilities
        Added value: +{
        +  "items": {
        +    "additionalProperties": {},
        +    "properties": {
        +      "_spell": {
        +        "description": "Mongo `_id` reference (24-character hex string).",
        +        "minLength": 1,
        +        "type": "string"
        +      },
        +      "level": {
        +        "maximum": 20,
        +        "minimum": 1,
        +        "type": "integer"
        +      }
        +    },
        +    "type": "object"
        +  },
        +  "type": "array"
        +}
      • addedInput schema / properties / spellChoices
        Added value: +{
        +  "items": {
        +    "additionalProperties": {},
        +    "properties": {
        +      "allowedCategories": {
        +        "items": {
        +          "type": "string"
        +        },
        +        "type": "array"
        +      },
        +      "allowedSchools": {
        +        "items": {
        +          "type": "string"
        +        },
        +        "type": "array"
        +      },
        +      "allowedSpells": {
        +        "items": {
        +          "description": "Mongo `_id` reference (24-character hex string).",
        +          "minLength": 1,
        +          "type": "string"
        +        },
        +        "type": "array"
        +      },
        +      "castingAbility": {
        +        "enum": [
        +          "strength",
        +          "dexterity",
        +          "constitution",
        +          "intelligence",
        +          "wisdom",
        +          "charisma"
        +        ],
        +        "type": "string"
        +      },
        +      "castingAbilityOptions": {
        +        "items": {
        +          "enum": [
        +            "strength",
        +            "dexterity",
        +            "constitution",
        +            "intelligence",
        +            "wisdom",
        +            "charisma"
        +          ],
        +          "type": "string"
        +        },
        +        "type": "array"
        +      },
        +      "freeCast": {
        +        "additionalProperties": {},
        +        "properties": {
        +          "atWill": {
        +            "type": "boolean"
        +          },
        +          "count": {
        +            "maximum": 9007199254740991,
        +            "minimum": 0,
        +            "type": "integer"
        +          },
        +          "progression": {
        +            "items": {
        +              "additionalProperties": {},
        +              "properties": {
        +                "count": {
        +                  "maximum": 9007199254740991,
        +                  "minimum": 0,
        +                  "type": "integer"
        +                },
        +                "level": {
        +                  "maximum": 20,
        +                  "minimum": 1,
        +                  "type": "integer"
        +                }
        +              },
        +              "type": "object"
        +            },
        +            "type": "array"
        +          },
        +          "recovery": {
        +            "items": {
        +              "additionalProperties": {},
        +              "properties": {
        +                "count": {
        +                  "maximum": 9007199254740991,
        +                  "minimum": 0,
        +                  "type": "integer"
        +                },
        +                "on": {
        +                  "enum": [
        +                    "Short",
        +                    "Long"
        +                  ],
        +                  "type": "string"
        +                },
        +                "restoreAll": {
        +                  "type": "boolean"
        +                }
        +              },
        +              "type": "object"
        +            },
        +            "type": "array"
        +          }
        +        },
        +        "type": "object"
        +      },
        +      "label": {
        +        "type": "string"
        +      },
        +      "maxLevel": {
        +        "maximum": 9,
        +        "minimum": 0,
        +        "type": "integer"
        +      },
        +      "minLevel": {
        +        "maximum": 9,
        +        "minimum": 0,
        +        "type": "integer"
        +      },
        +      "mode": {
        +        "enum": [
        +          "filter",
        +          "specific"
        +        ],
        +        "type": "string"
        +      },
        +      "prepared": {
        +        "type": "boolean"
        +      },
        +      "progression": {
        +        "items": {
        +          "additionalProperties": {},
        +          "properties": {
        +            "count": {
        +              "maximum": 9007199254740991,
        +              "minimum": 0,
        +              "type": "integer"
        +            },
        +            "level": {
        +              "maximum": 20,
        +              "minimum": 1,
        +              "type": "integer"
        +            }
        +          },
        +          "type": "object"
        +        },
        +        "type": "array"
        +      }
        +    },
        +    "type": "object"
        +  },
        +  "type": "array"
        +}
      • addedInput schema / properties / spellListChoices
        Added value: +{
        +  "items": {
        +    "additionalProperties": {},
        +    "properties": {
        +      "allowedCategories": {
        +        "items": {
        +          "type": "string"
        +        },
        +        "type": "array"
        +      },
        +      "castingAbility": {
        +        "enum": [
        +          "strength",
        +          "dexterity",
        +          "constitution",
        +          "intelligence",
        +          "wisdom",
        +          "charisma"
        +        ],
        +        "type": "string"
        +      },
        +      "castingAbilityOptions": {
        +        "items": {
        +          "enum": [
        +            "strength",
        +            "dexterity",
        +            "constitution",
        +            "intelligence",
        +            "wisdom",
        +            "charisma"
        +          ],
        +          "type": "string"
        +        },
        +        "type": "array"
        +      },
        +      "label": {
        +        "type": "string"
        +      },
        +      "picks": {
        +        "items": {
        +          "additionalProperties": {},
        +          "properties": {
        +            "count": {
        +              "maximum": 9007199254740991,
        +              "minimum": 0,
        +              "type": "integer"
        +            },
        +            "freeCast": {
        +              "additionalProperties": {},
        +              "properties": {
        +                "atWill": {
        +                  "type": "boolean"
        +                },
        +                "count": {
        +                  "maximum": 9007199254740991,
        +                  "minimum": 0,
        +                  "type": "integer"
        +                },
        +                "progression": {
        +                  "items": {
        +                    "additionalProperties": {},
        +                    "properties": {
        +                      "count": {
        +                        "maximum": 9007199254740991,
        +                        "minimum": 0,
        +                        "type": "integer"
        +                      },
        +                      "level": {
        +                        "maximum": 20,
        +                        "minimum": 1,
        +                        "type": "integer"
        +                      }
        +                    },
        +                    "type": "object"
        +                  },
        +                  "type": "array"
        +                },
        +                "recovery": {
        +                  "items": {
        +                    "additionalProperties": {},
        +                    "properties": {
        +                      "count": {
        +                        "maximum": 9007199254740991,
        +                        "minimum": 0,
        +                        "type": "integer"
        +                      },
        +                      "on": {
        +                        "enum": [
        +                          "Short",
        +                          "Long"
        +                        ],
        +                        "type": "string"
        +                      },
        +                      "restoreAll": {
        +                        "type": "boolean"
        +                      }
        +                    },
        +                    "type": "object"
        +                  },
        +                  "type": "array"
        +                }
        +              },
        +              "type": "object"
        +            },
        +            "label": {
        +              "type": "string"
        +            },
        +            "maxLevel": {
        +              "maximum": 9,
        +              "minimum": 0,
        +              "type": "integer"
        +            },
        +            "minLevel": {
        +              "maximum": 9,
        +              "minimum": 0,
        +              "type": "integer"
        +            }
        +          },
        +          "type": "object"
        +        },
        +        "type": "array"
        +      },
        +      "prepared": {
        +        "type": "boolean"
        +      }
        +    },
        +    "type": "object"
        +  },
        +  "type": "array"
        +}
      • addedInput schema / properties / startingEquipment
        Added value: +{
        +  "items": {
        +    "additionalProperties": {},
        +    "properties": {
        +      "items": {
        +        "items": {
        +          "additionalProperties": {},
        +          "properties": {
        +            "_item": {
        +              "description": "Mongo `_id` reference (24-character hex string).",
        +              "minLength": 1,
        +              "type": "string"
        +            },
        +            "quantity": {
        +              "maximum": 9007199254740991,
        +              "minimum": 0,
        +              "type": "integer"
        +            }
        +          },
        +          "type": "object"
        +        },
        +        "type": "array"
        +      },
        +      "label": {
        +        "type": "string"
        +      }
        +    },
        +    "type": "object"
        +  },
        +  "type": "array"
        +}
      • addedInput schema / properties / statBonuses
        Added value: +{
        +  "items": {
        +    "additionalProperties": {},
        +    "properties": {
        +      "attribute": {
        +        "description": "For valueType: 'attribute' — which ability's modifier to use.",
        +        "type": "string"
        +      },
        +      "audience": {
        +        "description": "Who the bonus contributes to. Absent = self.",
        +        "enum": [
        +          "self",
        +          "ally",
        +          "any",
        +          "target",
        +          "enemy"
        +        ],
        +        "type": "string"
        +      },
        +      "dice": {
        +        "description": "For valueType: 'dice' — dice expression (e.g. '1d4').",
        +        "type": "string"
        +      },
        +      "durationCount": {
        +        "description": "Numeric count paired with durationUnit (e.g. count: 3, unit: 'round').",
        +        "maximum": 9007199254740991,
        +        "minimum": 0,
        +        "type": "integer"
        +      },
        +      "durationUnit": {
        +        "description": "How long the bonus persists once fired. Only meaningful for event-driven bonuses.",
        +        "enum": [
        +          "instantaneous",
        +          "untilStartOfNextTurn",
        +          "untilEndOfNextTurn",
        +          "round",
        +          "minute",
        +          "hour",
        +          "untilShortRest",
        +          "untilLongRest"
        +        ],
        +        "type": "string"
        +      },
        +      "fixed": {
        +        "description": "For valueType: 'fixed' — the literal numeric contribution.",
        +        "type": "number"
        +      },
        +      "progression": {
        +        "description": "For valueType: 'byLevel' — per-level rows; walker picks the row with level <= current level.",
        +        "items": {
        +          "additionalProperties": {},
        +          "properties": {
        +            "dice": {
        +              "type": "string"
        +            },
        +            "flat": {
        +              "type": "number"
        +            },
        +            "level": {
        +              "maximum": 20,
        +              "minimum": 1,
        +              "type": "integer"
        +            }
        +          },
        +          "type": "object"
        +        },
        +        "type": "array"
        +      },
        +      "range": {
        +        "description": "Aura radius in feet for ally/any-audience bonuses (Aura of Protection's 10 ft.). Absent = no range filter.",
        +        "maximum": 9007199254740991,
        +        "minimum": 0,
        +        "type": "integer"
        +      },
        +      "requires": {
        +        "description": "Optional predicate list that gates this bonus. Absent / empty = always-on.",
        +        "items": {
        +          "additionalProperties": {},
        +          "properties": {
        +            "armorCategories": {
        +              "description": "For 'equipped' + slot:armor: armor category list (Light / Medium / Heavy). OR semantics — match any.",
        +              "items": {
        +                "type": "string"
        +              },
        +              "type": "array"
        +            },
        +            "condition": {
        +              "description": "For 'condition' predicates: the character-state condition to gate on (5e24 named conditions and ongoing-action states).",
        +              "enum": [
        +                "blinded",
        +                "charmed",
        +                "dazed",
        +                "deafened",
        +                "exhaustion",
        +                "frightened",
        +                "grappled",
        +                "incapacitated",
        +                "invisible",
        +                "paralyzed",
        +                "petrified",
        +                "poisoned",
        +                "prone",
        +                "restrained",
        +                "stunned",
        +                "unconscious",
        +                "concentrating",
        +                "grappling",
        +                "dodging",
        +                "hiding",
        +                "raging"
        +              ],
        +              "type": "string"
        +            },
        +            "equipSlot": {
        +              "description": "Body slot the matched weapon must occupy. mainHand / offHand. Resolved via getRequiredSlots so two-handed grips occupy both.",
        +              "enum": [
        +                "mainHand",
        +                "offHand"
        +              ],
        +              "type": "string"
        +            },
        +            "negate": {
        +              "description": "true inverts the predicate — 'while NOT matching' instead of 'while matching'.",
        +              "type": "boolean"
        +            },
        +            "slot": {
        +              "description": "For 'equipped' predicates: the body category to match (armor / shield / weapon).",
        +              "enum": [
        +                "armor",
        +                "shield",
        +                "weapon"
        +              ],
        +              "type": "string"
        +            },
        +            "type": {
        +              "description": "Predicate type. 'equipped' = character-scoped (gates on what's equipped). 'attackingWeapon' = attack-scoped (gates on the current action's source weapon). 'condition' = gates on a character-state condition.",
        +              "enum": [
        +                "equipped",
        +                "attackingWeapon",
        +                "condition"
        +              ],
        +              "type": "string"
        +            },
        +            "weaponProperties": {
        +              "description": "For 'equipped' + slot:weapon OR 'attackingWeapon': weapon-property list. AND semantics — match all.",
        +              "items": {
        +                "type": "string"
        +              },
        +              "type": "array"
        +            }
        +          },
        +          "type": "object"
        +        },
        +        "type": "array"
        +      },
        +      "requiresLogic": {
        +        "description": "How `requires` predicates compose. 'and' (default) = ALL must hold. 'or' = ANY one is sufficient.",
        +        "enum": [
        +          "and",
        +          "or"
        +        ],
        +        "type": "string"
        +      },
        +      "target": {
        +        "description": "Stat the bonus contributes to (e.g. 'skills.Acrobatics.misc', 'attributes.strength.misc').",
        +        "type": "string"
        +      },
        +      "trigger": {
        +        "description": "Action-economy / cost shape of the bonus. passive / toggled / reaction / perRoll / resource / targetBound.",
        +        "enum": [
        +          "passive",
        +          "toggled",
        +          "reaction",
        +          "perRoll",
        +          "resource",
        +          "targetBound"
        +        ],
        +        "type": "string"
        +      },
        +      "triggerEvent": {
        +        "description": "Game-time event that fires the bonus (onHit / onDamage / startOfYourTurn / etc.). Absent = not event-driven (passive walker contributes whenever `requires` holds).",
        +        "enum": [
        +          "onHit",
        +          "onMiss",
        +          "onDamage",
        +          "startOfYourTurn",
        +          "endOfYourTurn",
        +          "startOfTargetTurn",
        +          "endOfTargetTurn"
        +        ],
        +        "type": "string"
        +      },
        +      "types": {
        +        "description": "Damage type tags for damage.* targets. No-op for non-damage targets.",
        +        "items": {
        +          "type": "string"
        +        },
        +        "type": "array"
        +      },
        +      "valueType": {
        +        "description": "How the contribution is computed. 'fixed' uses `fixed`; 'attribute' uses the mod of `attribute`; 'attackAttribute' uses the action's attack-roll ability (per-attack only); others scale by level/PB/dice.",
        +        "enum": [
        +          "fixed",
        +          "attribute",
        +          "proficiency",
        +          "level",
        +          "halfLevel",
        +          "dice",
        +          "byLevel",
        +          "attackAttribute"
        +        ],
        +        "type": "string"
        +      }
        +    },
        +    "type": "object"
        +  },
        +  "type": "array"
        +}
      • addedInput schema / properties / summary
        Added value: +{
        +  "description": "Short one-line summary.",
        +  "type": "string"
        +}
      • addedInput schema / properties / toolChoices
        Added value: +{
        +  "additionalProperties": {},
        +  "properties": {
        +    "count": {
        +      "maximum": 9007199254740991,
        +      "minimum": 0,
        +      "type": "integer"
        +    },
        +    "options": {
        +      "items": {
        +        "type": "string"
        +      },
        +      "type": "array"
        +    }
        +  },
        +  "type": "object"
        +}
      • addedInput schema / properties / toolProficiencies
        Added value: +{
        +  "items": {
        +    "type": "string"
        +  },
        +  "type": "array"
        +}
      • addedInput schema / properties / type
        Added value: +{
        +  "description": "Rule category. Required at create time; vault rejects without it.",
        +  "enum": [
        +    "Ability",
        +    "Feat",
        +    "Action Card",
        +    "Hindrance",
        +    "Edge",
        +    "Class",
        +    "Background",
        +    "Race",
        +    "Species",
        +    "Ancestry",
        +    "Glossary",
        +    "Stunt",
        +    "Extra"
        +  ],
        +  "type": "string"
        +}
      • addedInput schema / properties / uses
        Added value: +{
        +  "items": {
        +    "additionalProperties": {},
        +    "properties": {
        +      "count": {
        +        "maximum": 9007199254740991,
        +        "minimum": 0,
        +        "type": "integer"
        +      },
        +      "mode": {
        +        "enum": [
        +          "fixed",
        +          "byLevel",
        +          "proficiency"
        +        ],
        +        "type": "string"
        +      },
        +      "name": {
        +        "type": "string"
        +      },
        +      "progression": {
        +        "items": {
        +          "additionalProperties": {},
        +          "properties": {
        +            "count": {
        +              "maximum": 9007199254740991,
        +              "minimum": 0,
        +              "type": "integer"
        +            },
        +            "countAbility": {
        +              "enum": [
        +                "strength",
        +                "dexterity",
        +                "constitution",
        +                "intelligence",
        +                "wisdom",
        +                "charisma"
        +              ],
        +              "type": "string"
        +            },
        +            "countSource": {
        +              "enum": [
        +                "fixed",
        +                "proficiency",
        +                "abilityMod"
        +              ],
        +              "type": "string"
        +            },
        +            "level": {
        +              "maximum": 20,
        +              "minimum": 1,
        +              "type": "integer"
        +            },
        +            "slotLevel": {
        +              "maximum": 9,
        +              "minimum": 1,
        +              "type": "integer"
        +            }
        +          },
        +          "type": "object"
        +        },
        +        "type": "array"
        +      },
        +      "recovery": {
        +        "items": {
        +          "additionalProperties": {},
        +          "properties": {
        +            "count": {
        +              "maximum": 9007199254740991,
        +              "minimum": 0,
        +              "type": "integer"
        +            },
        +            "on": {
        +              "enum": [
        +                "Short",
        +                "Long"
        +              ],
        +              "type": "string"
        +            },
        +            "restoreAll": {
        +              "type": "boolean"
        +            }
        +          },
        +          "type": "object"
        +        },
        +        "type": "array"
        +      },
        +      "rest": {
        +        "enum": [
        +          "Short",
        +          "Long"
        +        ],
        +        "type": "string"
        +      },
        +      "slotLevel": {
        +        "maximum": 9,
        +        "minimum": 1,
        +        "type": "integer"
        +      }
        +    },
        +    "type": "object"
        +  },
        +  "type": "array"
        +}
      • addedInput schema / properties / weaponProficiencies
        Added value: +{
        +  "items": {
        +    "type": "string"
        +  },
        +  "type": "array"
        +}
      • addedInput schema / required
        Added value: +[
        +  "id",
        +  "baseUpdatedAt"
        +]
    • Changedvault_update_spell53 fields changed
      • addedInput schema / $schema
        Added value: +"http://json-schema.org/draft-07/schema#"
      • addedInput schema / additionalProperties
        Added value: +{}
      • addedInput schema / properties / _parent
        Added value: +{
        +  "description": "Parent spell ObjectId for variant spells.",
        +  "minLength": 1,
        +  "type": "string"
        +}
      • addedInput schema / properties / abilityScoreBump
        Added value: +{
        +  "additionalProperties": {},
        +  "properties": {
        +    "options": {
        +      "description": "Alternatives the player picks exactly ONE of (OR).",
        +      "items": {
        +        "additionalProperties": {},
        +        "properties": {
        +          "lines": {
        +            "description": "Lines that ALL apply when this option is chosen (AND).",
        +            "items": {
        +              "additionalProperties": {},
        +              "properties": {
        +                "amount": {
        +                  "description": "How much each chosen ability goes up (usually positive).",
        +                  "type": "number"
        +                },
        +                "count": {
        +                  "description": "How many distinct abilities this line raises.",
        +                  "maximum": 9007199254740991,
        +                  "minimum": 1,
        +                  "type": "integer"
        +                },
        +                "eligible": {
        +                  "description": "Pool to choose from. Empty / absent = any of the six.",
        +                  "items": {
        +                    "enum": [
        +                      "strength",
        +                      "dexterity",
        +                      "constitution",
        +                      "intelligence",
        +                      "wisdom",
        +                      "charisma"
        +                    ],
        +                    "type": "string"
        +                  },
        +                  "type": "array"
        +                },
        +                "max": {
        +                  "description": "Ceiling no chosen score may exceed after the bump (ASI = 20).",
        +                  "maximum": 9007199254740991,
        +                  "minimum": 1,
        +                  "type": "integer"
        +                }
        +              },
        +              "type": "object"
        +            },
        +            "type": "array"
        +          }
        +        },
        +        "type": "object"
        +      },
        +      "type": "array"
        +    }
        +  },
        +  "type": "object"
        +}
      • addedInput schema / properties / abilityScoreSet
        Added value: +{
        +  "items": {
        +    "additionalProperties": {},
        +    "properties": {
        +      "ability": {
        +        "enum": [
        +          "strength",
        +          "dexterity",
        +          "constitution",
        +          "intelligence",
        +          "wisdom",
        +          "charisma"
        +        ],
        +        "type": "string"
        +      },
        +      "value": {
        +        "description": "Score to set the ability to while in effect.",
        +        "maximum": 9007199254740991,
        +        "minimum": 1,
        +        "type": "integer"
        +      }
        +    },
        +    "type": "object"
        +  },
        +  "type": "array"
        +}
      • addedInput schema / properties / actionType
        Added value: +{
        +  "description": "Authoring hint — when set, the character sheet's rule modal shows an 'Add to Actions' button that mints an action row with this `type`.",
        +  "type": "string"
        +}
      • addedInput schema / properties / actions
        Added value: +{
        +  "description": "PF Playtest action-economy marker (F/1/2/3/R).",
        +  "type": "string"
        +}
      • addedInput schema / properties / active
        Added value: +{
        +  "type": "boolean"
        +}
      • addedInput schema / properties / area
        Added value: +{
        +  "additionalProperties": {},
        +  "description": "Area of effect. shape ∈ cone|cube|cylinder|emanation|line|sphere; size (ft); width for line.",
        +  "properties": {
        +    "shape": {
        +      "enum": [
        +        "cone",
        +        "cube",
        +        "cylinder",
        +        "emanation",
        +        "line",
        +        "sphere"
        +      ],
        +      "type": "string"
        +    },
        +    "size": {
        +      "minimum": 0,
        +      "type": "number"
        +    },
        +    "width": {
        +      "minimum": 0,
        +      "type": "number"
        +    }
        +  },
        +  "type": "object"
        +}
      • addedInput schema / properties / baseUpdatedAt
        Added value: +{
        +  "description": "REQUIRED proof that you are working from the latest version: copy the `updatedAt` value verbatim from a FRESH read of this exact record (use the matching get tool first). Values from memory, from an earlier conversation, or guessed timestamps are rejected with OUT_OF_SYNC and nothing is written. After a successful update, the response carries the new `updatedAt` — use that for any follow-up write.",
        +  "minLength": 1,
        +  "type": "string"
        +}
      • addedInput schema / properties / castingTime
        Added value: +{
        +  "additionalProperties": {},
        +  "description": "Casting time. unit ∈ action|bonusAction|reaction|minute|hour; count for minute/hour.",
        +  "properties": {
        +    "count": {
        +      "maximum": 9007199254740991,
        +      "minimum": 0,
        +      "type": "integer"
        +    },
        +    "unit": {
        +      "enum": [
        +        "action",
        +        "bonusAction",
        +        "reaction",
        +        "minute",
        +        "hour"
        +      ],
        +      "type": "string"
        +    }
        +  },
        +  "type": "object"
        +}
      • addedInput schema / properties / categories
        Added value: +{
        +  "description": "Go-forward class membership. The field `spellChoices[].allowedCategories` filters on; the vault UI labels it 'Class(es)'. Free-form, taggable.",
        +  "items": {
        +    "type": "string"
        +  },
        +  "type": "array"
        +}
      • addedInput schema / properties / classes
        Added value: +{
        +  "description": "Class-membership list for non-5.5e rulesets (e.g. PFRPG); 5.5e spells use `categories` instead. Free-form per ruleset.",
        +  "items": {
        +    "type": "string"
        +  },
        +  "type": "array"
        +}
      • addedInput schema / properties / components
        Added value: +{
        +  "additionalProperties": {},
        +  "description": "Components: verbal/somatic/material flags, plus material text, gp cost, and consumed flag.",
        +  "properties": {
        +    "material": {
        +      "type": "boolean"
        +    },
        +    "materialConsumed": {
        +      "type": "boolean"
        +    },
        +    "materialCost": {
        +      "minimum": 0,
        +      "type": "number"
        +    },
        +    "materialText": {
        +      "type": "string"
        +    },
        +    "somatic": {
        +      "type": "boolean"
        +    },
        +    "verbal": {
        +      "type": "boolean"
        +    }
        +  },
        +  "type": "object"
        +}
      • addedInput schema / properties / damage
        Added value: +{
        +  "additionalProperties": {},
        +  "properties": {
        +    "appliesTo": {
        +      "enum": [
        +        "melee",
        +        "ranged",
        +        "either"
        +      ],
        +      "type": "string"
        +    },
        +    "area": {
        +      "items": {
        +        "additionalProperties": {},
        +        "properties": {
        +          "shape": {
        +            "enum": [
        +              "cone",
        +              "line",
        +              "sphere",
        +              "cube",
        +              "cylinder",
        +              "emanation",
        +              "radius"
        +            ],
        +            "type": "string"
        +          },
        +          "size": {
        +            "minimum": 0,
        +            "type": "number"
        +          },
        +          "width": {
        +            "minimum": 0,
        +            "type": "number"
        +          }
        +        },
        +        "type": "object"
        +      },
        +      "type": "array"
        +    },
        +    "dice": {
        +      "type": "string"
        +    },
        +    "flat": {
        +      "type": "number"
        +    },
        +    "modifierAbility": {
        +      "enum": [
        +        "strength",
        +        "dexterity",
        +        "constitution",
        +        "intelligence",
        +        "wisdom",
        +        "charisma"
        +      ],
        +      "type": "string"
        +    },
        +    "modifierType": {
        +      "enum": [
        +        "flat",
        +        "proficiency",
        +        "ability"
        +      ],
        +      "type": "string"
        +    },
        +    "onSave": {
        +      "enum": [
        +        "half",
        +        "negates",
        +        "full"
        +      ],
        +      "type": "string"
        +    },
        +    "progression": {
        +      "items": {
        +        "additionalProperties": {},
        +        "properties": {
        +          "dice": {
        +            "type": "string"
        +          },
        +          "flat": {
        +            "type": "number"
        +          },
        +          "level": {
        +            "maximum": 20,
        +            "minimum": 1,
        +            "type": "integer"
        +          }
        +        },
        +        "type": "object"
        +      },
        +      "type": "array"
        +    },
        +    "save": {
        +      "additionalProperties": {},
        +      "properties": {
        +        "ability": {
        +          "enum": [
        +            "none",
        +            "spellcasting",
        +            "attackAttribute",
        +            "strength",
        +            "dexterity",
        +            "constitution",
        +            "intelligence",
        +            "wisdom",
        +            "charisma"
        +          ],
        +          "type": "string"
        +        },
        +        "dcBase": {
        +          "type": "number"
        +        },
        +        "includesProficiency": {
        +          "type": "boolean"
        +        },
        +        "saveType": {
        +          "enum": [
        +            "strength",
        +            "dexterity",
        +            "constitution",
        +            "intelligence",
        +            "wisdom",
        +            "charisma"
        +          ],
        +          "type": "string"
        +        }
        +      },
        +      "type": "object"
        +    },
        +    "scaling": {
        +      "enum": [
        +        "fixed",
        +        "byLevel",
        +        "spellSlot"
        +      ],
        +      "type": "string"
        +    },
        +    "scalingAttribute": {
        +      "type": "string"
        +    },
        +    "slotIncrement": {
        +      "additionalProperties": {},
        +      "properties": {
        +        "dice": {
        +          "type": "string"
        +        },
        +        "flat": {
        +          "type": "number"
        +        },
        +        "targets": {
        +          "maximum": 9007199254740991,
        +          "minimum": 1,
        +          "type": "integer"
        +        }
        +      },
        +      "type": "object"
        +    },
        +    "targets": {
        +      "additionalProperties": {},
        +      "properties": {
        +        "count": {
        +          "maximum": 9007199254740991,
        +          "minimum": 1,
        +          "type": "integer"
        +        }
        +      },
        +      "type": "object"
        +    },
        +    "trigger": {
        +      "enum": [
        +        "passive",
        +        "toggled",
        +        "reaction",
        +        "perRoll",
        +        "resource",
        +        "targetBound"
        +      ],
        +      "type": "string"
        +    },
        +    "types": {
        +      "items": {
        +        "type": "string"
        +      },
        +      "type": "array"
        +    }
        +  },
        +  "type": "object"
        +}
      • addedInput schema / properties / damageReduction
        Added value: +{
        +  "items": {
        +    "additionalProperties": {},
        +    "properties": {
        +      "amount": {
        +        "additionalProperties": {},
        +        "properties": {
        +          "dice": {
        +            "type": "string"
        +          },
        +          "flat": {
        +            "type": "number"
        +          },
        +          "includesProficiency": {
        +            "type": "boolean"
        +          },
        +          "modifierSource": {
        +            "enum": [
        +              "spellcasting",
        +              "attackAttribute",
        +              "strength",
        +              "dexterity",
        +              "constitution",
        +              "intelligence",
        +              "wisdom",
        +              "charisma"
        +            ],
        +            "type": "string"
        +          }
        +        },
        +        "type": "object"
        +      },
        +      "range": {
        +        "maximum": 9007199254740991,
        +        "minimum": 0,
        +        "type": "integer"
        +      },
        +      "requires": {
        +        "items": {
        +          "additionalProperties": {},
        +          "properties": {
        +            "armorCategories": {
        +              "description": "For 'equipped' + slot:armor: armor category list (Light / Medium / Heavy). OR semantics — match any.",
        +              "items": {
        +                "type": "string"
        +              },
        +              "type": "array"
        +            },
        +            "condition": {
        +              "description": "For 'condition' predicates: the character-state condition to gate on (5e24 named conditions and ongoing-action states).",
        +              "enum": [
        +                "blinded",
        +                "charmed",
        +                "dazed",
        +                "deafened",
        +                "exhaustion",
        +                "frightened",
        +                "grappled",
        +                "incapacitated",
        +                "invisible",
        +                "paralyzed",
        +                "petrified",
        +                "poisoned",
        +                "prone",
        +                "restrained",
        +                "stunned",
        +                "unconscious",
        +                "concentrating",
        +                "grappling",
        +                "dodging",
        +                "hiding",
        +                "raging"
        +              ],
        +              "type": "string"
        +            },
        +            "equipSlot": {
        +              "description": "Body slot the matched weapon must occupy. mainHand / offHand. Resolved via getRequiredSlots so two-handed grips occupy both.",
        +              "enum": [
        +                "mainHand",
        +                "offHand"
        +              ],
        +              "type": "string"
        +            },
        +            "negate": {
        +              "description": "true inverts the predicate — 'while NOT matching' instead of 'while matching'.",
        +              "type": "boolean"
        +            },
        +            "slot": {
        +              "description": "For 'equipped' predicates: the body category to match (armor / shield / weapon).",
        +              "enum": [
        +                "armor",
        +                "shield",
        +                "weapon"
        +              ],
        +              "type": "string"
        +            },
        +            "type": {
        +              "description": "Predicate type. 'equipped' = character-scoped (gates on what's equipped). 'attackingWeapon' = attack-scoped (gates on the current action's source weapon). 'condition' = gates on a character-state condition.",
        +              "enum": [
        +                "equipped",
        +                "attackingWeapon",
        +                "condition"
        +              ],
        +              "type": "string"
        +            },
        +            "weaponProperties": {
        +              "description": "For 'equipped' + slot:weapon OR 'attackingWeapon': weapon-property list. AND semantics — match all.",
        +              "items": {
        +                "type": "string"
        +              },
        +              "type": "array"
        +            }
        +          },
        +          "type": "object"
        +        },
        +        "type": "array"
        +      },
        +      "requiresLogic": {
        +        "enum": [
        +          "and",
        +          "or"
        +        ],
        +        "type": "string"
        +      },
        +      "target": {
        +        "enum": [
        +          "self",
        +          "ally",
        +          "any",
        +          "target",
        +          "enemy"
        +        ],
        +        "type": "string"
        +      },
        +      "trigger": {
        +        "enum": [
        +          "passive",
        +          "toggled",
        +          "reaction",
        +          "perRoll",
        +          "resource",
        +          "targetBound"
        +        ],
        +        "type": "string"
        +      },
        +      "types": {
        +        "items": {
        +          "type": "string"
        +        },
        +        "type": "array"
        +      }
        +    },
        +    "type": "object"
        +  },
        +  "type": "array"
        +}
      • addedInput schema / properties / description
        Added value: +{
        +  "description": "Full spell body. Markdown is supported.",
        +  "type": "string"
        +}
      • addedInput schema / properties / diceFloors
        Added value: +{
        +  "items": {
        +    "additionalProperties": {},
        +    "properties": {
        +      "appliesTo": {
        +        "enum": [
        +          "damage",
        +          "damage.melee",
        +          "damage.ranged",
        +          "damage.spell",
        +          "healing"
        +        ],
        +        "type": "string"
        +      },
        +      "floor": {
        +        "maximum": 9007199254740991,
        +        "minimum": 1,
        +        "type": "integer"
        +      },
        +      "requires": {
        +        "items": {
        +          "additionalProperties": {},
        +          "properties": {
        +            "armorCategories": {
        +              "description": "For 'equipped' + slot:armor: armor category list (Light / Medium / Heavy). OR semantics — match any.",
        +              "items": {
        +                "type": "string"
        +              },
        +              "type": "array"
        +            },
        +            "condition": {
        +              "description": "For 'condition' predicates: the character-state condition to gate on (5e24 named conditions and ongoing-action states).",
        +              "enum": [
        +                "blinded",
        +                "charmed",
        +                "dazed",
        +                "deafened",
        +                "exhaustion",
        +                "frightened",
        +                "grappled",
        +                "incapacitated",
        +                "invisible",
        +                "paralyzed",
        +                "petrified",
        +                "poisoned",
        +                "prone",
        +                "restrained",
        +                "stunned",
        +                "unconscious",
        +                "concentrating",
        +                "grappling",
        +                "dodging",
        +                "hiding",
        +                "raging"
        +              ],
        +              "type": "string"
        +            },
        +            "equipSlot": {
        +              "description": "Body slot the matched weapon must occupy. mainHand / offHand. Resolved via getRequiredSlots so two-handed grips occupy both.",
        +              "enum": [
        +                "mainHand",
        +                "offHand"
        +              ],
        +              "type": "string"
        +            },
        +            "negate": {
        +              "description": "true inverts the predicate — 'while NOT matching' instead of 'while matching'.",
        +              "type": "boolean"
        +            },
        +            "slot": {
        +              "description": "For 'equipped' predicates: the body category to match (armor / shield / weapon).",
        +              "enum": [
        +                "armor",
        +                "shield",
        +                "weapon"
        +              ],
        +              "type": "string"
        +            },
        +            "type": {
        +              "description": "Predicate type. 'equipped' = character-scoped (gates on what's equipped). 'attackingWeapon' = attack-scoped (gates on the current action's source weapon). 'condition' = gates on a character-state condition.",
        +              "enum": [
        +                "equipped",
        +                "attackingWeapon",
        +                "condition"
        +              ],
        +              "type": "string"
        +            },
        +            "weaponProperties": {
        +              "description": "For 'equipped' + slot:weapon OR 'attackingWeapon': weapon-property list. AND semantics — match all.",
        +              "items": {
        +                "type": "string"
        +              },
        +              "type": "array"
        +            }
        +          },
        +          "type": "object"
        +        },
        +        "type": "array"
        +      },
        +      "requiresLogic": {
        +        "enum": [
        +          "and",
        +          "or"
        +        ],
        +        "type": "string"
        +      },
        +      "threshold": {
        +        "maximum": 9007199254740991,
        +        "minimum": 1,
        +        "type": "integer"
        +      },
        +      "trigger": {
        +        "enum": [
        +          "passive",
        +          "toggled",
        +          "reaction",
        +          "perRoll",
        +          "resource",
        +          "targetBound"
        +        ],
        +        "type": "string"
        +      }
        +    },
        +    "type": "object"
        +  },
        +  "type": "array"
        +}
      • addedInput schema / properties / diceReplacements
        Added value: +{
        +  "items": {
        +    "additionalProperties": {},
        +    "properties": {
        +      "_target": {
        +        "description": "Mongo `_id` reference (24-character hex string).",
        +        "minLength": 1,
        +        "type": "string"
        +      },
        +      "dice": {
        +        "type": "string"
        +      },
        +      "progression": {
        +        "items": {
        +          "additionalProperties": {},
        +          "properties": {
        +            "dice": {
        +              "type": "string"
        +            },
        +            "level": {
        +              "maximum": 20,
        +              "minimum": 1,
        +              "type": "integer"
        +            }
        +          },
        +          "type": "object"
        +        },
        +        "type": "array"
        +      },
        +      "requires": {
        +        "items": {
        +          "additionalProperties": {},
        +          "properties": {
        +            "armorCategories": {
        +              "description": "For 'equipped' + slot:armor: armor category list (Light / Medium / Heavy). OR semantics — match any.",
        +              "items": {
        +                "type": "string"
        +              },
        +              "type": "array"
        +            },
        +            "condition": {
        +              "description": "For 'condition' predicates: the character-state condition to gate on (5e24 named conditions and ongoing-action states).",
        +              "enum": [
        +                "blinded",
        +                "charmed",
        +                "dazed",
        +                "deafened",
        +                "exhaustion",
        +                "frightened",
        +                "grappled",
        +                "incapacitated",
        +                "invisible",
        +                "paralyzed",
        +                "petrified",
        +                "poisoned",
        +                "prone",
        +                "restrained",
        +                "stunned",
        +                "unconscious",
        +                "concentrating",
        +                "grappling",
        +                "dodging",
        +                "hiding",
        +                "raging"
        +              ],
        +              "type": "string"
        +            },
        +            "equipSlot": {
        +              "description": "Body slot the matched weapon must occupy. mainHand / offHand. Resolved via getRequiredSlots so two-handed grips occupy both.",
        +              "enum": [
        +                "mainHand",
        +                "offHand"
        +              ],
        +              "type": "string"
        +            },
        +            "negate": {
        +              "description": "true inverts the predicate — 'while NOT matching' instead of 'while matching'.",
        +              "type": "boolean"
        +            },
        +            "slot": {
        +              "description": "For 'equipped' predicates: the body category to match (armor / shield / weapon).",
        +              "enum": [
        +                "armor",
        +                "shield",
        +                "weapon"
        +              ],
        +              "type": "string"
        +            },
        +            "type": {
        +              "description": "Predicate type. 'equipped' = character-scoped (gates on what's equipped). 'attackingWeapon' = attack-scoped (gates on the current action's source weapon). 'condition' = gates on a character-state condition.",
        +              "enum": [
        +                "equipped",
        +                "attackingWeapon",
        +                "condition"
        +              ],
        +              "type": "string"
        +            },
        +            "weaponProperties": {
        +              "description": "For 'equipped' + slot:weapon OR 'attackingWeapon': weapon-property list. AND semantics — match all.",
        +              "items": {
        +                "type": "string"
        +              },
        +              "type": "array"
        +            }
        +          },
        +          "type": "object"
        +        },
        +        "type": "array"
        +      },
        +      "requiresLogic": {
        +        "enum": [
        +          "and",
        +          "or"
        +        ],
        +        "type": "string"
        +      }
        +    },
        +    "type": "object"
        +  },
        +  "type": "array"
        +}
      • addedInput schema / properties / duration
        Added value: +{
        +  "additionalProperties": {},
        +  "description": "Spell duration. unit ∈ instantaneous | round | minute | hour | day | untilDispelled | untilDispelledOrTriggered | special; count for timed units; concentration flag; upTo flag for a non-concentration capped duration (\"Up to 1 minute\").",
        +  "properties": {
        +    "concentration": {
        +      "type": "boolean"
        +    },
        +    "count": {
        +      "maximum": 9007199254740991,
        +      "minimum": 0,
        +      "type": "integer"
        +    },
        +    "unit": {
        +      "enum": [
        +        "instantaneous",
        +        "round",
        +        "minute",
        +        "hour",
        +        "day",
        +        "untilDispelled",
        +        "untilDispelledOrTriggered",
        +        "special"
        +      ],
        +      "type": "string"
        +    },
        +    "upTo": {
        +      "type": "boolean"
        +    }
        +  },
        +  "type": "object"
        +}
      • addedInput schema / properties / effect
        Added value: +{
        +  "additionalProperties": {},
        +  "properties": {
        +    "audience": {
        +      "enum": [
        +        "self",
        +        "ally",
        +        "any",
        +        "target",
        +        "enemy"
        +      ],
        +      "type": "string"
        +    },
        +    "conditions": {
        +      "items": {
        +        "additionalProperties": {},
        +        "properties": {
        +          "applyWhen": {
        +            "enum": [
        +              "always",
        +              "onFail",
        +              "onSuccess"
        +            ],
        +            "type": "string"
        +          },
        +          "durationCount": {
        +            "maximum": 9007199254740991,
        +            "minimum": 0,
        +            "type": "integer"
        +          },
        +          "durationUnit": {
        +            "enum": [
        +              "round",
        +              "minute",
        +              "hour",
        +              "day",
        +              "untilShortRest",
        +              "untilLongRest",
        +              "special"
        +            ],
        +            "type": "string"
        +          },
        +          "name": {
        +            "type": "string"
        +          },
        +          "target": {
        +            "enum": [
        +              "self",
        +              "target"
        +            ],
        +            "type": "string"
        +          }
        +        },
        +        "type": "object"
        +      },
        +      "type": "array"
        +    },
        +    "save": {
        +      "additionalProperties": {},
        +      "properties": {
        +        "ability": {
        +          "enum": [
        +            "none",
        +            "spellcasting",
        +            "attackAttribute",
        +            "strength",
        +            "dexterity",
        +            "constitution",
        +            "intelligence",
        +            "wisdom",
        +            "charisma"
        +          ],
        +          "type": "string"
        +        },
        +        "dcBase": {
        +          "type": "number"
        +        },
        +        "includesProficiency": {
        +          "type": "boolean"
        +        },
        +        "saveType": {
        +          "enum": [
        +            "strength",
        +            "dexterity",
        +            "constitution",
        +            "intelligence",
        +            "wisdom",
        +            "charisma"
        +          ],
        +          "type": "string"
        +        }
        +      },
        +      "type": "object"
        +    },
        +    "triggerEvent": {
        +      "enum": [
        +        "onHit",
        +        "onMiss",
        +        "onDamage",
        +        "startOfYourTurn",
        +        "endOfYourTurn",
        +        "startOfTargetTurn",
        +        "endOfTargetTurn"
        +      ],
        +      "type": "string"
        +    }
        +  },
        +  "type": "object"
        +}
      • addedInput schema / properties / forcedMovement
        Added value: +{
        +  "items": {
        +    "additionalProperties": {},
        +    "properties": {
        +      "audience": {
        +        "enum": [
        +          "self",
        +          "ally",
        +          "any",
        +          "target",
        +          "enemy"
        +        ],
        +        "type": "string"
        +      },
        +      "direction": {
        +        "enum": [
        +          "awayFromSelf",
        +          "towardSelf",
        +          "anywhere"
        +        ],
        +        "type": "string"
        +      },
        +      "distance": {
        +        "maximum": 9007199254740991,
        +        "minimum": 0,
        +        "type": "integer"
        +      },
        +      "maxTargetSize": {
        +        "enum": [
        +          "tiny",
        +          "small",
        +          "medium",
        +          "large",
        +          "huge",
        +          "gargantuan"
        +        ],
        +        "type": "string"
        +      },
        +      "requires": {
        +        "items": {
        +          "additionalProperties": {},
        +          "properties": {
        +            "armorCategories": {
        +              "description": "For 'equipped' + slot:armor: armor category list (Light / Medium / Heavy). OR semantics — match any.",
        +              "items": {
        +                "type": "string"
        +              },
        +              "type": "array"
        +            },
        +            "condition": {
        +              "description": "For 'condition' predicates: the character-state condition to gate on (5e24 named conditions and ongoing-action states).",
        +              "enum": [
        +                "blinded",
        +                "charmed",
        +                "dazed",
        +                "deafened",
        +                "exhaustion",
        +                "frightened",
        +                "grappled",
        +                "incapacitated",
        +                "invisible",
        +                "paralyzed",
        +                "petrified",
        +                "poisoned",
        +                "prone",
        +                "restrained",
        +                "stunned",
        +                "unconscious",
        +                "concentrating",
        +                "grappling",
        +                "dodging",
        +                "hiding",
        +                "raging"
        +              ],
        +              "type": "string"
        +            },
        +            "equipSlot": {
        +              "description": "Body slot the matched weapon must occupy. mainHand / offHand. Resolved via getRequiredSlots so two-handed grips occupy both.",
        +              "enum": [
        +                "mainHand",
        +                "offHand"
        +              ],
        +              "type": "string"
        +            },
        +            "negate": {
        +              "description": "true inverts the predicate — 'while NOT matching' instead of 'while matching'.",
        +              "type": "boolean"
        +            },
        +            "slot": {
        +              "description": "For 'equipped' predicates: the body category to match (armor / shield / weapon).",
        +              "enum": [
        +                "armor",
        +                "shield",
        +                "weapon"
        +              ],
        +              "type": "string"
        +            },
        +            "type": {
        +              "description": "Predicate type. 'equipped' = character-scoped (gates on what's equipped). 'attackingWeapon' = attack-scoped (gates on the current action's source weapon). 'condition' = gates on a character-state condition.",
        +              "enum": [
        +                "equipped",
        +                "attackingWeapon",
        +                "condition"
        +              ],
        +              "type": "string"
        +            },
        +            "weaponProperties": {
        +              "description": "For 'equipped' + slot:weapon OR 'attackingWeapon': weapon-property list. AND semantics — match all.",
        +              "items": {
        +                "type": "string"
        +              },
        +              "type": "array"
        +            }
        +          },
        +          "type": "object"
        +        },
        +        "type": "array"
        +      },
        +      "requiresLogic": {
        +        "enum": [
        +          "and",
        +          "or"
        +        ],
        +        "type": "string"
        +      },
        +      "triggerEvent": {
        +        "enum": [
        +          "onHit",
        +          "onMiss",
        +          "onDamage",
        +          "startOfYourTurn",
        +          "endOfYourTurn",
        +          "startOfTargetTurn",
        +          "endOfTargetTurn"
        +        ],
        +        "type": "string"
        +      }
        +    },
        +    "type": "object"
        +  },
        +  "type": "array"
        +}
      • addedInput schema / properties / healing
        Added value: +{
        +  "additionalProperties": {},
        +  "properties": {
        +    "dice": {
        +      "type": "string"
        +    },
        +    "flat": {
        +      "type": "number"
        +    },
        +    "modifierSource": {
        +      "enum": [
        +        "level",
        +        "spellcasting",
        +        "strength",
        +        "dexterity",
        +        "constitution",
        +        "intelligence",
        +        "wisdom",
        +        "charisma"
        +      ],
        +      "type": "string"
        +    },
        +    "progression": {
        +      "items": {
        +        "additionalProperties": {},
        +        "properties": {
        +          "dice": {
        +            "type": "string"
        +          },
        +          "flat": {
        +            "type": "number"
        +          },
        +          "level": {
        +            "maximum": 20,
        +            "minimum": 1,
        +            "type": "integer"
        +          }
        +        },
        +        "type": "object"
        +      },
        +      "type": "array"
        +    },
        +    "scaling": {
        +      "enum": [
        +        "fixed",
        +        "byLevel",
        +        "proficiency",
        +        "spellSlot"
        +      ],
        +      "type": "string"
        +    },
        +    "slotIncrement": {
        +      "additionalProperties": {},
        +      "properties": {
        +        "dice": {
        +          "type": "string"
        +        },
        +        "flat": {
        +          "type": "number"
        +        }
        +      },
        +      "type": "object"
        +    },
        +    "target": {
        +      "enum": [
        +        "self",
        +        "ally",
        +        "any",
        +        "multiple"
        +      ],
        +      "type": "string"
        +    },
        +    "targets": {
        +      "additionalProperties": {},
        +      "properties": {
        +        "count": {
        +          "maximum": 9007199254740991,
        +          "minimum": 1,
        +          "type": "integer"
        +        }
        +      },
        +      "type": "object"
        +    }
        +  },
        +  "type": "object"
        +}
      • addedInput schema / properties / higherLevel
        Added value: +{
        +  "description": "Higher-Level / cantrip-scaling text (what changes when cast with a higher slot).",
        +  "type": "string"
        +}
      • addedInput schema / properties / id
        Added value: +{
        +  "description": "Mongo `_id` of the spell to update.",
        +  "minLength": 1,
        +  "type": "string"
        +}
      • addedInput schema / properties / level
        Added value: +{
        +  "description": "Spell level. 0 for cantrips; 1–9 for leveled spells (5e/5e24).",
        +  "maximum": 9007199254740991,
        +  "minimum": -9007199254740991,
        +  "type": "integer"
        +}
      • addedInput schema / properties / mechanicsKey
        Added value: +{
        +  "type": "string"
        +}
      • addedInput schema / properties / name
        Added value: +{
        +  "description": "Display name.",
        +  "minLength": 1,
        +  "type": "string"
        +}
      • addedInput schema / properties / ogl
        Added value: +{
        +  "type": "boolean"
        +}
      • addedInput schema / properties / parameters
        Added value: +{
        +  "items": {
        +    "additionalProperties": {},
        +    "properties": {
        +      "label": {
        +        "type": "string"
        +      },
        +      "max": {
        +        "type": "number"
        +      },
        +      "min": {
        +        "type": "number"
        +      },
        +      "name": {
        +        "type": "string"
        +      },
        +      "type": {
        +        "enum": [
        +          "number",
        +          "string",
        +          "enum"
        +        ],
        +        "type": "string"
        +      },
        +      "unit": {
        +        "type": "string"
        +      }
        +    },
        +    "type": "object"
        +  },
        +  "type": "array"
        +}
      • addedInput schema / properties / preparedSpells
        Added value: +{
        +  "additionalProperties": {},
        +  "properties": {
        +    "count": {
        +      "maximum": 9007199254740991,
        +      "minimum": 0,
        +      "type": "integer"
        +    },
        +    "progression": {
        +      "items": {
        +        "additionalProperties": {},
        +        "properties": {
        +          "count": {
        +            "maximum": 9007199254740991,
        +            "minimum": 0,
        +            "type": "integer"
        +          },
        +          "level": {
        +            "maximum": 20,
        +            "minimum": 1,
        +            "type": "integer"
        +          }
        +        },
        +        "type": "object"
        +      },
        +      "type": "array"
        +    }
        +  },
        +  "type": "object"
        +}
      • addedInput schema / properties / prerequisites
        Added value: +{
        +  "items": {
        +    "additionalProperties": {},
        +    "properties": {
        +      "abilities": {
        +        "description": "For abilityScore: ANY listed ability meeting `min` satisfies ('Str or Dex 13+').",
        +        "items": {
        +          "enum": [
        +            "strength",
        +            "dexterity",
        +            "constitution",
        +            "intelligence",
        +            "wisdom",
        +            "charisma"
        +          ],
        +          "type": "string"
        +        },
        +        "type": "array"
        +      },
        +      "category": {
        +        "description": "For rule (filter): matches any held rule in this category.",
        +        "type": "string"
        +      },
        +      "class": {
        +        "description": "For a `level` predicate: a Class rule id that scopes `min` to 'Nth level in that class'. Absent = total character level.",
        +        "minLength": 1,
        +        "type": "string"
        +      },
        +      "min": {
        +        "description": "Numeric minimum — character level (level), class level (class), or ability score (abilityScore).",
        +        "maximum": 9007199254740991,
        +        "minimum": 0,
        +        "type": "integer"
        +      },
        +      "negate": {
        +        "description": "true inverts the predicate — 'must NOT meet this'.",
        +        "type": "boolean"
        +      },
        +      "proficiency": {
        +        "description": "For proficiency: the proficiency name (e.g. 'Martial', 'Stealth').",
        +        "type": "string"
        +      },
        +      "proficiencyType": {
        +        "description": "For proficiency: the family.",
        +        "enum": [
        +          "skill",
        +          "tool",
        +          "weapon",
        +          "armor",
        +          "save",
        +          "language"
        +        ],
        +        "type": "string"
        +      },
        +      "rule": {
        +        "description": "For rule: a specific held Rule id.",
        +        "minLength": 1,
        +        "type": "string"
        +      },
        +      "ruleType": {
        +        "description": "For rule (filter): matches any held rule of this type.",
        +        "type": "string"
        +      },
        +      "spell": {
        +        "description": "For spell: a specific known Spell id.",
        +        "minLength": 1,
        +        "type": "string"
        +      },
        +      "spellList": {
        +        "description": "For spell (filter): knows any spell from this class list.",
        +        "type": "string"
        +      },
        +      "type": {
        +        "description": "Predicate kind: level / abilityScore / rule / spell / proficiency / spellcasting. (A class is required via a `rule` predicate pointing at the class rule.)",
        +        "enum": [
        +          "level",
        +          "abilityScore",
        +          "rule",
        +          "spell",
        +          "proficiency",
        +          "spellcasting"
        +        ],
        +        "type": "string"
        +      }
        +    },
        +    "type": "object"
        +  },
        +  "type": "array"
        +}
      • addedInput schema / properties / prerequisitesLogic
        Added value: +{
        +  "enum": [
        +    "and",
        +    "or"
        +  ],
        +  "type": "string"
        +}
      • addedInput schema / properties / proficiencyChoices
        Added value: +{
        +  "items": {
        +    "additionalProperties": {},
        +    "properties": {
        +      "allowedItems": {
        +        "items": {
        +          "type": "string"
        +        },
        +        "type": "array"
        +      },
        +      "level": {
        +        "enum": [
        +          "proficient",
        +          "expertise"
        +        ],
        +        "type": "string"
        +      },
        +      "mode": {
        +        "enum": [
        +          "specific",
        +          "all"
        +        ],
        +        "type": "string"
        +      },
        +      "progression": {
        +        "items": {
        +          "additionalProperties": {},
        +          "properties": {
        +            "count": {
        +              "maximum": 9007199254740991,
        +              "minimum": 0,
        +              "type": "integer"
        +            },
        +            "level": {
        +              "maximum": 20,
        +              "minimum": 1,
        +              "type": "integer"
        +            }
        +          },
        +          "type": "object"
        +        },
        +        "type": "array"
        +      },
        +      "types": {
        +        "items": {
        +          "enum": [
        +            "skill",
        +            "tool",
        +            "save",
        +            "weapon",
        +            "armor",
        +            "language"
        +          ],
        +          "type": "string"
        +        },
        +        "type": "array"
        +      }
        +    },
        +    "type": "object"
        +  },
        +  "type": "array"
        +}
      • addedInput schema / properties / publisher
        Added value: +{
        +  "type": "string"
        +}
      • addedInput schema / properties / range
        Added value: +{
        +  "additionalProperties": {},
        +  "description": "Range. kind ∈ self|touch|ranged|sight|unlimited|special; distance for ranged; unit ∈ feet|miles (default feet).",
        +  "properties": {
        +    "distance": {
        +      "minimum": 0,
        +      "type": "number"
        +    },
        +    "kind": {
        +      "enum": [
        +        "self",
        +        "touch",
        +        "ranged",
        +        "sight",
        +        "unlimited",
        +        "special"
        +      ],
        +      "type": "string"
        +    },
        +    "unit": {
        +      "enum": [
        +        "feet",
        +        "miles"
        +      ],
        +      "type": "string"
        +    }
        +  },
        +  "type": "object"
        +}
      • addedInput schema / properties / rank
        Added value: +{
        +  "description": "PFRPG2 rank field. Free-form.",
        +  "type": "string"
        +}
      • addedInput schema / properties / reactionTrigger
        Added value: +{
        +  "description": "When castingTime.unit is 'reaction', the trigger text ('which you take when…').",
        +  "type": "string"
        +}
      • addedInput schema / properties / recurringDamage
        Added value: +{
        +  "items": {
        +    "additionalProperties": {},
        +    "properties": {
        +      "amount": {
        +        "additionalProperties": {},
        +        "properties": {
        +          "dice": {
        +            "type": "string"
        +          },
        +          "flat": {
        +            "type": "number"
        +          },
        +          "includesProficiency": {
        +            "type": "boolean"
        +          },
        +          "modifierSource": {
        +            "enum": [
        +              "spellcasting",
        +              "attackAttribute",
        +              "strength",
        +              "dexterity",
        +              "constitution",
        +              "intelligence",
        +              "wisdom",
        +              "charisma"
        +            ],
        +            "type": "string"
        +          }
        +        },
        +        "type": "object"
        +      },
        +      "audience": {
        +        "enum": [
        +          "self",
        +          "ally",
        +          "any",
        +          "target",
        +          "enemy"
        +        ],
        +        "type": "string"
        +      },
        +      "durationCount": {
        +        "maximum": 9007199254740991,
        +        "minimum": 0,
        +        "type": "integer"
        +      },
        +      "durationUnit": {
        +        "enum": [
        +          "instantaneous",
        +          "untilStartOfNextTurn",
        +          "untilEndOfNextTurn",
        +          "round",
        +          "minute",
        +          "hour",
        +          "untilShortRest",
        +          "untilLongRest"
        +        ],
        +        "type": "string"
        +      },
        +      "ignoreResistances": {
        +        "type": "boolean"
        +      },
        +      "inheritDamageType": {
        +        "type": "boolean"
        +      },
        +      "range": {
        +        "maximum": 9007199254740991,
        +        "minimum": 0,
        +        "type": "integer"
        +      },
        +      "requires": {
        +        "items": {
        +          "additionalProperties": {},
        +          "properties": {
        +            "armorCategories": {
        +              "description": "For 'equipped' + slot:armor: armor category list (Light / Medium / Heavy). OR semantics — match any.",
        +              "items": {
        +                "type": "string"
        +              },
        +              "type": "array"
        +            },
        +            "condition": {
        +              "description": "For 'condition' predicates: the character-state condition to gate on (5e24 named conditions and ongoing-action states).",
        +              "enum": [
        +                "blinded",
        +                "charmed",
        +                "dazed",
        +                "deafened",
        +                "exhaustion",
        +                "frightened",
        +                "grappled",
        +                "incapacitated",
        +                "invisible",
        +                "paralyzed",
        +                "petrified",
        +                "poisoned",
        +                "prone",
        +                "restrained",
        +                "stunned",
        +                "unconscious",
        +                "concentrating",
        +                "grappling",
        +                "dodging",
        +                "hiding",
        +                "raging"
        +              ],
        +              "type": "string"
        +            },
        +            "equipSlot": {
        +              "description": "Body slot the matched weapon must occupy. mainHand / offHand. Resolved via getRequiredSlots so two-handed grips occupy both.",
        +              "enum": [
        +                "mainHand",
        +                "offHand"
        +              ],
        +              "type": "string"
        +            },
        +            "negate": {
        +              "description": "true inverts the predicate — 'while NOT matching' instead of 'while matching'.",
        +              "type": "boolean"
        +            },
        +            "slot": {
        +              "description": "For 'equipped' predicates: the body category to match (armor / shield / weapon).",
        +              "enum": [
        +                "armor",
        +                "shield",
        +                "weapon"
        +              ],
        +              "type": "string"
        +            },
        +            "type": {
        +              "description": "Predicate type. 'equipped' = character-scoped (gates on what's equipped). 'attackingWeapon' = attack-scoped (gates on the current action's source weapon). 'condition' = gates on a character-state condition.",
        +              "enum": [
        +                "equipped",
        +                "attackingWeapon",
        +                "condition"
        +              ],
        +              "type": "string"
        +            },
        +            "weaponProperties": {
        +              "description": "For 'equipped' + slot:weapon OR 'attackingWeapon': weapon-property list. AND semantics — match all.",
        +              "items": {
        +                "type": "string"
        +              },
        +              "type": "array"
        +            }
        +          },
        +          "type": "object"
        +        },
        +        "type": "array"
        +      },
        +      "requiresLogic": {
        +        "enum": [
        +          "and",
        +          "or"
        +        ],
        +        "type": "string"
        +      },
        +      "triggerEvent": {
        +        "enum": [
        +          "startOfYourTurn",
        +          "endOfYourTurn",
        +          "startOfTargetTurn",
        +          "endOfTargetTurn",
        +          "whenTargetEntersArea",
        +          "onHit",
        +          "onMiss",
        +          "onDamage"
        +        ],
        +        "type": "string"
        +      },
        +      "types": {
        +        "items": {
        +          "type": "string"
        +        },
        +        "type": "array"
        +      }
        +    },
        +    "type": "object"
        +  },
        +  "type": "array"
        +}
      • addedInput schema / properties / resistances
        Added value: +{
        +  "items": {
        +    "additionalProperties": {},
        +    "properties": {
        +      "mode": {
        +        "enum": [
        +          "resistance",
        +          "immunity",
        +          "vulnerability"
        +        ],
        +        "type": "string"
        +      },
        +      "range": {
        +        "description": "Aura radius in feet for ally/any-targeted resistances (Warding Aura's 10 ft.). Absent = self-only.",
        +        "maximum": 9007199254740991,
        +        "minimum": 0,
        +        "type": "integer"
        +      },
        +      "target": {
        +        "description": "Who the resistance protects — mirrors damageReduction's target/range pair. Absent = self.",
        +        "enum": [
        +          "self",
        +          "ally",
        +          "any",
        +          "target",
        +          "enemy"
        +        ],
        +        "type": "string"
        +      },
        +      "trigger": {
        +        "enum": [
        +          "passive",
        +          "toggled",
        +          "reaction",
        +          "perRoll",
        +          "resource",
        +          "targetBound"
        +        ],
        +        "type": "string"
        +      },
        +      "types": {
        +        "items": {
        +          "type": "string"
        +        },
        +        "type": "array"
        +      }
        +    },
        +    "type": "object"
        +  },
        +  "type": "array"
        +}
      • addedInput schema / properties / ritual
        Added value: +{
        +  "description": "5.5e ritual tag — the spell can be cast as a ritual (no spell slot).",
        +  "type": "boolean"
        +}
      • addedInput schema / properties / rollMods
        Added value: +{
        +  "items": {
        +    "additionalProperties": {},
        +    "properties": {
        +      "audience": {
        +        "enum": [
        +          "self",
        +          "ally",
        +          "any",
        +          "target",
        +          "enemy"
        +        ],
        +        "type": "string"
        +      },
        +      "consumeOnUse": {
        +        "type": "boolean"
        +      },
        +      "durationCount": {
        +        "maximum": 9007199254740991,
        +        "minimum": 0,
        +        "type": "integer"
        +      },
        +      "durationUnit": {
        +        "enum": [
        +          "instantaneous",
        +          "untilStartOfNextTurn",
        +          "untilEndOfNextTurn",
        +          "round",
        +          "minute",
        +          "hour",
        +          "untilShortRest",
        +          "untilLongRest"
        +        ],
        +        "type": "string"
        +      },
        +      "mode": {
        +        "enum": [
        +          "advantage",
        +          "disadvantage"
        +        ],
        +        "type": "string"
        +      },
        +      "range": {
        +        "maximum": 9007199254740991,
        +        "minimum": 0,
        +        "type": "integer"
        +      },
        +      "requires": {
        +        "items": {
        +          "additionalProperties": {},
        +          "properties": {
        +            "armorCategories": {
        +              "description": "For 'equipped' + slot:armor: armor category list (Light / Medium / Heavy). OR semantics — match any.",
        +              "items": {
        +                "type": "string"
        +              },
        +              "type": "array"
        +            },
        +            "condition": {
        +              "description": "For 'condition' predicates: the character-state condition to gate on (5e24 named conditions and ongoing-action states).",
        +              "enum": [
        +                "blinded",
        +                "charmed",
        +                "dazed",
        +                "deafened",
        +                "exhaustion",
        +                "frightened",
        +                "grappled",
        +                "incapacitated",
        +                "invisible",
        +                "paralyzed",
        +                "petrified",
        +                "poisoned",
        +                "prone",
        +                "restrained",
        +                "stunned",
        +                "unconscious",
        +                "concentrating",
        +                "grappling",
        +                "dodging",
        +                "hiding",
        +                "raging"
        +              ],
        +              "type": "string"
        +            },
        +            "equipSlot": {
        +              "description": "Body slot the matched weapon must occupy. mainHand / offHand. Resolved via getRequiredSlots so two-handed grips occupy both.",
        +              "enum": [
        +                "mainHand",
        +                "offHand"
        +              ],
        +              "type": "string"
        +            },
        +            "negate": {
        +              "description": "true inverts the predicate — 'while NOT matching' instead of 'while matching'.",
        +              "type": "boolean"
        +            },
        +            "slot": {
        +              "description": "For 'equipped' predicates: the body category to match (armor / shield / weapon).",
        +              "enum": [
        +                "armor",
        +                "shield",
        +                "weapon"
        +              ],
        +              "type": "string"
        +            },
        +            "type": {
        +              "description": "Predicate type. 'equipped' = character-scoped (gates on what's equipped). 'attackingWeapon' = attack-scoped (gates on the current action's source weapon). 'condition' = gates on a character-state condition.",
        +              "enum": [
        +                "equipped",
        +                "attackingWeapon",
        +                "condition"
        +              ],
        +              "type": "string"
        +            },
        +            "weaponProperties": {
        +              "description": "For 'equipped' + slot:weapon OR 'attackingWeapon': weapon-property list. AND semantics — match all.",
        +              "items": {
        +                "type": "string"
        +              },
        +              "type": "array"
        +            }
        +          },
        +          "type": "object"
        +        },
        +        "type": "array"
        +      },
        +      "requiresLogic": {
        +        "enum": [
        +          "and",
        +          "or"
        +        ],
        +        "type": "string"
        +      },
        +      "rollScope": {
        +        "enum": [
        +          "attack",
        +          "save",
        +          "abilityCheck",
        +          "skillCheck"
        +        ],
        +        "type": "string"
        +      },
        +      "trigger": {
        +        "enum": [
        +          "passive",
        +          "toggled",
        +          "reaction",
        +          "perRoll",
        +          "resource",
        +          "targetBound"
        +        ],
        +        "type": "string"
        +      },
        +      "triggerEvent": {
        +        "enum": [
        +          "onHit",
        +          "onMiss",
        +          "onDamage",
        +          "startOfYourTurn",
        +          "endOfYourTurn",
        +          "startOfTargetTurn",
        +          "endOfTargetTurn"
        +        ],
        +        "type": "string"
        +      }
        +    },
        +    "type": "object"
        +  },
        +  "type": "array"
        +}
      • addedInput schema / properties / ruleChoice
        Added value: +{
        +  "additionalProperties": {},
        +  "properties": {
        +    "allowedCategories": {
        +      "items": {
        +        "type": "string"
        +      },
        +      "type": "array"
        +    },
        +    "allowedRuleParameters": {
        +      "additionalProperties": {
        +        "additionalProperties": {},
        +        "properties": {
        +          "damageType": {
        +            "type": "string"
        +          },
        +          "number": {
        +            "maximum": 9007199254740991,
        +            "minimum": 0,
        +            "type": "integer"
        +          },
        +          "range": {
        +            "maximum": 9007199254740991,
        +            "minimum": 0,
        +            "type": "integer"
        +          },
        +          "speed": {
        +            "maximum": 9007199254740991,
        +            "minimum": 0,
        +            "type": "integer"
        +          }
        +        },
        +        "type": "object"
        +      },
        +      "propertyNames": {
        +        "type": "string"
        +      },
        +      "type": "object"
        +    },
        +    "allowedRules": {
        +      "items": {
        +        "description": "Mongo `_id` reference (24-character hex string).",
        +        "minLength": 1,
        +        "type": "string"
        +      },
        +      "type": "array"
        +    },
        +    "allowedTypes": {
        +      "items": {
        +        "type": "string"
        +      },
        +      "type": "array"
        +    },
        +    "count": {
        +      "maximum": 9007199254740991,
        +      "minimum": 0,
        +      "type": "integer"
        +    },
        +    "label": {
        +      "type": "string"
        +    },
        +    "mode": {
        +      "enum": [
        +        "filter",
        +        "specific"
        +      ],
        +      "type": "string"
        +    },
        +    "progression": {
        +      "items": {
        +        "additionalProperties": {},
        +        "properties": {
        +          "count": {
        +            "maximum": 9007199254740991,
        +            "minimum": 0,
        +            "type": "integer"
        +          },
        +          "level": {
        +            "maximum": 20,
        +            "minimum": 1,
        +            "type": "integer"
        +          }
        +        },
        +        "type": "object"
        +      },
        +      "type": "array"
        +    },
        +    "scaling": {
        +      "enum": [
        +        "fixed",
        +        "byLevel"
        +      ],
        +      "type": "string"
        +    }
        +  },
        +  "type": "object"
        +}
      • addedInput schema / properties / ruleset
        Added value: +{
        +  "description": "Ruleset code (e.g. '5th Edition', '5e24', 'PFRPG', 'Savage Worlds').",
        +  "type": "string"
        +}
      • addedInput schema / properties / school
        Added value: +{
        +  "description": "Spell school (Abjuration, Conjuration, Divination, Enchantment, Evocation, Illusion, Necromancy, Transmutation).",
        +  "type": "string"
        +}
      • addedInput schema / properties / source
        Added value: +{
        +  "type": "string"
        +}
      • addedInput schema / properties / spellChoices
        Added value: +{
        +  "items": {
        +    "additionalProperties": {},
        +    "properties": {
        +      "allowedCategories": {
        +        "items": {
        +          "type": "string"
        +        },
        +        "type": "array"
        +      },
        +      "allowedSchools": {
        +        "items": {
        +          "type": "string"
        +        },
        +        "type": "array"
        +      },
        +      "allowedSpells": {
        +        "items": {
        +          "description": "Mongo `_id` reference (24-character hex string).",
        +          "minLength": 1,
        +          "type": "string"
        +        },
        +        "type": "array"
        +      },
        +      "castingAbility": {
        +        "enum": [
        +          "strength",
        +          "dexterity",
        +          "constitution",
        +          "intelligence",
        +          "wisdom",
        +          "charisma"
        +        ],
        +        "type": "string"
        +      },
        +      "castingAbilityOptions": {
        +        "items": {
        +          "enum": [
        +            "strength",
        +            "dexterity",
        +            "constitution",
        +            "intelligence",
        +            "wisdom",
        +            "charisma"
        +          ],
        +          "type": "string"
        +        },
        +        "type": "array"
        +      },
        +      "freeCast": {
        +        "additionalProperties": {},
        +        "properties": {
        +          "atWill": {
        +            "type": "boolean"
        +          },
        +          "count": {
        +            "maximum": 9007199254740991,
        +            "minimum": 0,
        +            "type": "integer"
        +          },
        +          "progression": {
        +            "items": {
        +              "additionalProperties": {},
        +              "properties": {
        +                "count": {
        +                  "maximum": 9007199254740991,
        +                  "minimum": 0,
        +                  "type": "integer"
        +                },
        +                "level": {
        +                  "maximum": 20,
        +                  "minimum": 1,
        +                  "type": "integer"
        +                }
        +              },
        +              "type": "object"
        +            },
        +            "type": "array"
        +          },
        +          "recovery": {
        +            "items": {
        +              "additionalProperties": {},
        +              "properties": {
        +                "count": {
        +                  "maximum": 9007199254740991,
        +                  "minimum": 0,
        +                  "type": "integer"
        +                },
        +                "on": {
        +                  "enum": [
        +                    "Short",
        +                    "Long"
        +                  ],
        +                  "type": "string"
        +                },
        +                "restoreAll": {
        +                  "type": "boolean"
        +                }
        +              },
        +              "type": "object"
        +            },
        +            "type": "array"
        +          }
        +        },
        +        "type": "object"
        +      },
        +      "label": {
        +        "type": "string"
        +      },
        +      "maxLevel": {
        +        "maximum": 9,
        +        "minimum": 0,
        +        "type": "integer"
        +      },
        +      "minLevel": {
        +        "maximum": 9,
        +        "minimum": 0,
        +        "type": "integer"
        +      },
        +      "mode": {
        +        "enum": [
        +          "filter",
        +          "specific"
        +        ],
        +        "type": "string"
        +      },
        +      "prepared": {
        +        "type": "boolean"
        +      },
        +      "progression": {
        +        "items": {
        +          "additionalProperties": {},
        +          "properties": {
        +            "count": {
        +              "maximum": 9007199254740991,
        +              "minimum": 0,
        +              "type": "integer"
        +            },
        +            "level": {
        +              "maximum": 20,
        +              "minimum": 1,
        +              "type": "integer"
        +            }
        +          },
        +          "type": "object"
        +        },
        +        "type": "array"
        +      }
        +    },
        +    "type": "object"
        +  },
        +  "type": "array"
        +}
      • addedInput schema / properties / spellListChoices
        Added value: +{
        +  "items": {
        +    "additionalProperties": {},
        +    "properties": {
        +      "allowedCategories": {
        +        "items": {
        +          "type": "string"
        +        },
        +        "type": "array"
        +      },
        +      "castingAbility": {
        +        "enum": [
        +          "strength",
        +          "dexterity",
        +          "constitution",
        +          "intelligence",
        +          "wisdom",
        +          "charisma"
        +        ],
        +        "type": "string"
        +      },
        +      "castingAbilityOptions": {
        +        "items": {
        +          "enum": [
        +            "strength",
        +            "dexterity",
        +            "constitution",
        +            "intelligence",
        +            "wisdom",
        +            "charisma"
        +          ],
        +          "type": "string"
        +        },
        +        "type": "array"
        +      },
        +      "label": {
        +        "type": "string"
        +      },
        +      "picks": {
        +        "items": {
        +          "additionalProperties": {},
        +          "properties": {
        +            "count": {
        +              "maximum": 9007199254740991,
        +              "minimum": 0,
        +              "type": "integer"
        +            },
        +            "freeCast": {
        +              "additionalProperties": {},
        +              "properties": {
        +                "atWill": {
        +                  "type": "boolean"
        +                },
        +                "count": {
        +                  "maximum": 9007199254740991,
        +                  "minimum": 0,
        +                  "type": "integer"
        +                },
        +                "progression": {
        +                  "items": {
        +                    "additionalProperties": {},
        +                    "properties": {
        +                      "count": {
        +                        "maximum": 9007199254740991,
        +                        "minimum": 0,
        +                        "type": "integer"
        +                      },
        +                      "level": {
        +                        "maximum": 20,
        +                        "minimum": 1,
        +                        "type": "integer"
        +                      }
        +                    },
        +                    "type": "object"
        +                  },
        +                  "type": "array"
        +                },
        +                "recovery": {
        +                  "items": {
        +                    "additionalProperties": {},
        +                    "properties": {
        +                      "count": {
        +                        "maximum": 9007199254740991,
        +                        "minimum": 0,
        +                        "type": "integer"
        +                      },
        +                      "on": {
        +                        "enum": [
        +                          "Short",
        +                          "Long"
        +                        ],
        +                        "type": "string"
        +                      },
        +                      "restoreAll": {
        +                        "type": "boolean"
        +                      }
        +                    },
        +                    "type": "object"
        +                  },
        +                  "type": "array"
        +                }
        +              },
        +              "type": "object"
        +            },
        +            "label": {
        +              "type": "string"
        +            },
        +            "maxLevel": {
        +              "maximum": 9,
        +              "minimum": 0,
        +              "type": "integer"
        +            },
        +            "minLevel": {
        +              "maximum": 9,
        +              "minimum": 0,
        +              "type": "integer"
        +            }
        +          },
        +          "type": "object"
        +        },
        +        "type": "array"
        +      },
        +      "prepared": {
        +        "type": "boolean"
        +      }
        +    },
        +    "type": "object"
        +  },
        +  "type": "array"
        +}
      • addedInput schema / properties / statBonuses
        Added value: +{
        +  "items": {
        +    "additionalProperties": {},
        +    "properties": {
        +      "attribute": {
        +        "description": "For valueType: 'attribute' — which ability's modifier to use.",
        +        "type": "string"
        +      },
        +      "audience": {
        +        "description": "Who the bonus contributes to. Absent = self.",
        +        "enum": [
        +          "self",
        +          "ally",
        +          "any",
        +          "target",
        +          "enemy"
        +        ],
        +        "type": "string"
        +      },
        +      "dice": {
        +        "description": "For valueType: 'dice' — dice expression (e.g. '1d4').",
        +        "type": "string"
        +      },
        +      "durationCount": {
        +        "description": "Numeric count paired with durationUnit (e.g. count: 3, unit: 'round').",
        +        "maximum": 9007199254740991,
        +        "minimum": 0,
        +        "type": "integer"
        +      },
        +      "durationUnit": {
        +        "description": "How long the bonus persists once fired. Only meaningful for event-driven bonuses.",
        +        "enum": [
        +          "instantaneous",
        +          "untilStartOfNextTurn",
        +          "untilEndOfNextTurn",
        +          "round",
        +          "minute",
        +          "hour",
        +          "untilShortRest",
        +          "untilLongRest"
        +        ],
        +        "type": "string"
        +      },
        +      "fixed": {
        +        "description": "For valueType: 'fixed' — the literal numeric contribution.",
        +        "type": "number"
        +      },
        +      "progression": {
        +        "description": "For valueType: 'byLevel' — per-level rows; walker picks the row with level <= current level.",
        +        "items": {
        +          "additionalProperties": {},
        +          "properties": {
        +            "dice": {
        +              "type": "string"
        +            },
        +            "flat": {
        +              "type": "number"
        +            },
        +            "level": {
        +              "maximum": 20,
        +              "minimum": 1,
        +              "type": "integer"
        +            }
        +          },
        +          "type": "object"
        +        },
        +        "type": "array"
        +      },
        +      "range": {
        +        "description": "Aura radius in feet for ally/any-audience bonuses (Aura of Protection's 10 ft.). Absent = no range filter.",
        +        "maximum": 9007199254740991,
        +        "minimum": 0,
        +        "type": "integer"
        +      },
        +      "requires": {
        +        "description": "Optional predicate list that gates this bonus. Absent / empty = always-on.",
        +        "items": {
        +          "additionalProperties": {},
        +          "properties": {
        +            "armorCategories": {
        +              "description": "For 'equipped' + slot:armor: armor category list (Light / Medium / Heavy). OR semantics — match any.",
        +              "items": {
        +                "type": "string"
        +              },
        +              "type": "array"
        +            },
        +            "condition": {
        +              "description": "For 'condition' predicates: the character-state condition to gate on (5e24 named conditions and ongoing-action states).",
        +              "enum": [
        +                "blinded",
        +                "charmed",
        +                "dazed",
        +                "deafened",
        +                "exhaustion",
        +                "frightened",
        +                "grappled",
        +                "incapacitated",
        +                "invisible",
        +                "paralyzed",
        +                "petrified",
        +                "poisoned",
        +                "prone",
        +                "restrained",
        +                "stunned",
        +                "unconscious",
        +                "concentrating",
        +                "grappling",
        +                "dodging",
        +                "hiding",
        +                "raging"
        +              ],
        +              "type": "string"
        +            },
        +            "equipSlot": {
        +              "description": "Body slot the matched weapon must occupy. mainHand / offHand. Resolved via getRequiredSlots so two-handed grips occupy both.",
        +              "enum": [
        +                "mainHand",
        +                "offHand"
        +              ],
        +              "type": "string"
        +            },
        +            "negate": {
        +              "description": "true inverts the predicate — 'while NOT matching' instead of 'while matching'.",
        +              "type": "boolean"
        +            },
        +            "slot": {
        +              "description": "For 'equipped' predicates: the body category to match (armor / shield / weapon).",
        +              "enum": [
        +                "armor",
        +                "shield",
        +                "weapon"
        +              ],
        +              "type": "string"
        +            },
        +            "type": {
        +              "description": "Predicate type. 'equipped' = character-scoped (gates on what's equipped). 'attackingWeapon' = attack-scoped (gates on the current action's source weapon). 'condition' = gates on a character-state condition.",
        +              "enum": [
        +                "equipped",
        +                "attackingWeapon",
        +                "condition"
        +              ],
        +              "type": "string"
        +            },
        +            "weaponProperties": {
        +              "description": "For 'equipped' + slot:weapon OR 'attackingWeapon': weapon-property list. AND semantics — match all.",
        +              "items": {
        +                "type": "string"
        +              },
        +              "type": "array"
        +            }
        +          },
        +          "type": "object"
        +        },
        +        "type": "array"
        +      },
        +      "requiresLogic": {
        +        "description": "How `requires` predicates compose. 'and' (default) = ALL must hold. 'or' = ANY one is sufficient.",
        +        "enum": [
        +          "and",
        +          "or"
        +        ],
        +        "type": "string"
        +      },
        +      "target": {
        +        "description": "Stat the bonus contributes to (e.g. 'skills.Acrobatics.misc', 'attributes.strength.misc').",
        +        "type": "string"
        +      },
        +      "trigger": {
        +        "description": "Action-economy / cost shape of the bonus. passive / toggled / reaction / perRoll / resource / targetBound.",
        +        "enum": [
        +          "passive",
        +          "toggled",
        +          "reaction",
        +          "perRoll",
        +          "resource",
        +          "targetBound"
        +        ],
        +        "type": "string"
        +      },
        +      "triggerEvent": {
        +        "description": "Game-time event that fires the bonus (onHit / onDamage / startOfYourTurn / etc.). Absent = not event-driven (passive walker contributes whenever `requires` holds).",
        +        "enum": [
        +          "onHit",
        +          "onMiss",
        +          "onDamage",
        +          "startOfYourTurn",
        +          "endOfYourTurn",
        +          "startOfTargetTurn",
        +          "endOfTargetTurn"
        +        ],
        +        "type": "string"
        +      },
        +      "types": {
        +        "description": "Damage type tags for damage.* targets. No-op for non-damage targets.",
        +        "items": {
        +          "type": "string"
        +        },
        +        "type": "array"
        +      },
        +      "valueType": {
        +        "description": "How the contribution is computed. 'fixed' uses `fixed`; 'attribute' uses the mod of `attribute`; 'attackAttribute' uses the action's attack-roll ability (per-attack only); others scale by level/PB/dice.",
        +        "enum": [
        +          "fixed",
        +          "attribute",
        +          "proficiency",
        +          "level",
        +          "halfLevel",
        +          "dice",
        +          "byLevel",
        +          "attackAttribute"
        +        ],
        +        "type": "string"
        +      }
        +    },
        +    "type": "object"
        +  },
        +  "type": "array"
        +}
      • addedInput schema / properties / summary
        Added value: +{
        +  "description": "Short one-line summary.",
        +  "type": "string"
        +}
      • addedInput schema / properties / type
        Added value: +{
        +  "description": "Spell type. 5e / 5e24 use 'Spell'; Savage Worlds uses 'Power'. Required at create.",
        +  "enum": [
        +    "Spell",
        +    "Power"
        +  ],
        +  "type": "string"
        +}
      • addedInput schema / properties / uses
        Added value: +{
        +  "items": {
        +    "additionalProperties": {},
        +    "properties": {
        +      "count": {
        +        "maximum": 9007199254740991,
        +        "minimum": 0,
        +        "type": "integer"
        +      },
        +      "mode": {
        +        "enum": [
        +          "fixed",
        +          "byLevel",
        +          "proficiency"
        +        ],
        +        "type": "string"
        +      },
        +      "name": {
        +        "type": "string"
        +      },
        +      "progression": {
        +        "items": {
        +          "additionalProperties": {},
        +          "properties": {
        +            "count": {
        +              "maximum": 9007199254740991,
        +              "minimum": 0,
        +              "type": "integer"
        +            },
        +            "countAbility": {
        +              "enum": [
        +                "strength",
        +                "dexterity",
        +                "constitution",
        +                "intelligence",
        +                "wisdom",
        +                "charisma"
        +              ],
        +              "type": "string"
        +            },
        +            "countSource": {
        +              "enum": [
        +                "fixed",
        +                "proficiency",
        +                "abilityMod"
        +              ],
        +              "type": "string"
        +            },
        +            "level": {
        +              "maximum": 20,
        +              "minimum": 1,
        +              "type": "integer"
        +            },
        +            "slotLevel": {
        +              "maximum": 9,
        +              "minimum": 1,
        +              "type": "integer"
        +            }
        +          },
        +          "type": "object"
        +        },
        +        "type": "array"
        +      },
        +      "recovery": {
        +        "items": {
        +          "additionalProperties": {},
        +          "properties": {
        +            "count": {
        +              "maximum": 9007199254740991,
        +              "minimum": 0,
        +              "type": "integer"
        +            },
        +            "on": {
        +              "enum": [
        +                "Short",
        +                "Long"
        +              ],
        +              "type": "string"
        +            },
        +            "restoreAll": {
        +              "type": "boolean"
        +            }
        +          },
        +          "type": "object"
        +        },
        +        "type": "array"
        +      },
        +      "rest": {
        +        "enum": [
        +          "Short",
        +          "Long"
        +        ],
        +        "type": "string"
        +      },
        +      "slotLevel": {
        +        "maximum": 9,
        +        "minimum": 1,
        +        "type": "integer"
        +      }
        +    },
        +    "type": "object"
        +  },
        +  "type": "array"
        +}
      • addedInput schema / required
        Added value: +[
        +  "id",
        +  "baseUpdatedAt"
        +]
  4. 1 tool update
    • Changedimagine_unlink_world_from_campaign1 field changed
      • changedInput schema / properties / removeSyncedHouseRules / description
        Previous value: -"When true, additionally cleans up any house rules that were synced into the world when the campaign was originally linked. Default false."New value: +"When true, also removes the house rules the link shared between the world and the campaign. Default false."
  5. 137 tool updates
    • First observedcreate_submission
    • First observedget_submission
    • First observedimagine_create_adventure
    • First observedimagine_create_adventure_page
    • First observedimagine_create_world
    • First observedimagine_create_world_page
    • First observedimagine_delete_adventure
    • First observedimagine_delete_adventure_page
    • First observedimagine_delete_world
    • First observedimagine_delete_world_page
    • First observedimagine_generate_draconic_name
    • First observedimagine_generate_npc
    • First observedimagine_get_adventure
    • First observedimagine_get_adventure_page
    • First observedimagine_get_adventure_pages
    • First observedimagine_get_adventure_recaps
    • First observedimagine_get_world
    • First observedimagine_get_world_page
    • First observedimagine_link_adventure_to_campaign
    • First observedimagine_link_world_to_campaign
    • First observedimagine_list_adventure_pages
    • First observedimagine_list_adventure_parts
    • First observedimagine_list_my_adventures
    • First observedimagine_list_my_worlds
    • First observedimagine_list_world_pages
    • First observedimagine_list_world_pages_by_tags
    • First observedimagine_replace_in_adventure_page
    • First observedimagine_search_world_pages
    • First observedimagine_unlink_adventure_from_campaign
    • First observedimagine_unlink_world_from_campaign
    • First observedimagine_update_adventure
    • First observedimagine_update_adventure_page
    • First observedimagine_update_world
    • First observedimagine_update_world_page
    • First observedlist_my_submissions
    • First observedlist_rulesets
    • First observedplay_accept_friend_request
    • First observedplay_add_campaign_character
    • First observedplay_add_campaign_item
    • First observedplay_add_campaign_leg
    • First observedplay_add_campaign_rule
    • First observedplay_add_campaign_spell
    • First observedplay_cancel_friend_request
    • First observedplay_check_recap_exists
    • First observedplay_consume_pbem_emails
    • First observedplay_create_campaign
    • First observedplay_create_move
    • First observedplay_create_page
    • First observedplay_create_session
    • First observedplay_decline_friend_request
    • First observedplay_delete_campaign
    • First observedplay_delete_character
    • First observedplay_delete_move
    • First observedplay_delete_page
    • First observedplay_delete_session
    • First observedplay_disable_pbem_inbox
    • First observedplay_dismiss_pbem_email
    • First observedplay_enable_pbem_inbox
    • First observedplay_find_friend
    • First observedplay_get_campaign
    • First observedplay_get_character_note
    • First observedplay_get_move
    • First observedplay_get_page
    • First observedplay_get_session
    • First observedplay_invite_campaign_player
    • First observedplay_list_campaign_characters
    • First observedplay_list_campaign_companions
    • First observedplay_list_campaign_items
    • First observedplay_list_campaign_moves
    • First observedplay_list_campaign_players
    • First observedplay_list_campaign_rules
    • First observedplay_list_campaign_sessions
    • First observedplay_list_campaign_spells
    • First observedplay_list_my_campaigns
    • First observedplay_list_my_characters
    • First observedplay_list_my_friends
    • First observedplay_list_my_sessions
    • First observedplay_list_pages
    • First observedplay_list_participated_campaigns
    • First observedplay_list_pbem_inbox
    • First observedplay_list_pending_friends
    • First observedplay_list_session_moves
    • First observedplay_list_user_pages
    • First observedplay_regenerate_pbem_address
    • First observedplay_remove_campaign_item
    • First observedplay_remove_campaign_player
    • First observedplay_remove_campaign_rule
    • First observedplay_remove_campaign_spell
    • First observedplay_remove_friend
    • First observedplay_resolve_pbem_email
    • First observedplay_respond_to_campaign_invite
    • First observedplay_send_friend_request
    • First observedplay_set_campaign_leg_active
    • First observedplay_set_pbem_display_name
    • First observedplay_update_campaign
    • First observedplay_update_character_note
    • First observedplay_update_move
    • First observedplay_update_page
    • First observedplay_update_session
    • First observedreply_to_submission
    • First observedupload_submission_screenshot
    • First observedvault_attach_companion
    • First observedvault_build_monster
    • First observedvault_build_pc
    • First observedvault_clone_character
    • First observedvault_create_character
    • First observedvault_create_item
    • First observedvault_create_rule
    • First observedvault_create_spell
    • First observedvault_delete_character
    • First observedvault_delete_item
    • First observedvault_delete_rule
    • First observedvault_delete_spell
    • First observedvault_detach_companion
    • First observedvault_get_authoring_guide
    • First observedvault_get_character
    • First observedvault_get_item
    • First observedvault_get_levelup_options
    • First observedvault_get_pc_creation_options
    • First observedvault_get_rule
    • First observedvault_get_spell
    • First observedvault_level_up_pc
    • First observedvault_list_linked_characters
    • First observedvault_record_pc_classes
    • First observedvault_search_characters
    • First observedvault_search_items
    • First observedvault_search_monsters
    • First observedvault_search_rules
    • First observedvault_search_spells
    • First observedvault_spawn_linked_character
    • First observedvault_unlink_character
    • First observedvault_update_character
    • First observedvault_update_companion_state
    • First observedvault_update_item
    • First observedvault_update_rule
    • First observedvault_update_spell
    • First observedwhoami

Related MCP Connectors

Related MCP Servers

  • A
    license
    A
    quality
    B
    maintenance
    Holonovel turns a tabletop RPG rulebook and an AI client into a running game. The server enforces every rule and remembers your campaign as structured state the AI can't forget; the AI just narrates. D&D 5e, Starfinder, or any rulebook.
    33
    MIT
  • A
    license
    Not graded
    quality
    B
    maintenance
    Connect to your TTRPG campaign's repository and database. Instead of retrieving prose, its 48 tools (20 read, 28 write) return typed state: 14 entity schemas (NPCs, factions, locations, sessions, lore), relationship and knowledge-graph queries, wiki blocks, and a narrative-state bundle of open threads and canon facts.
    1
    MIT
  • A
    license
    Not graded
    quality
    D
    maintenance
    Provides read-only SRD lookup and deterministic enrichment tools for D&D 5e content generation, including search, entity retrieval, and generation of monsters, spells, items, NPCs, and encounters.
    MIT
Try in Browser

Glama MCP Gateway

Add one secure layer between your agents and this server.

Resources