Claude Code Plugins

Community-maintained marketplace

Feedback

edition-data-author

@Jasrags/ShadowMaster
1
0

Creates and validates catalog items for edition JSON files including spells, qualities, gear, augmentations, weapons, armor, adept powers, foci, and complex forms. Use when adding new items to core-rulebook.json or sourcebook files, or when validating existing catalog entries.

Install Skill

1Download skill
2Enable skills in Claude

Open claude.ai/settings/capabilities and find the "Skills" section

3Upload to Claude

Click "Upload skill" and select the downloaded ZIP file

Note: Please verify skill by going through its instructions before using it.

SKILL.md

name edition-data-author
description Creates and validates catalog items for edition JSON files including spells, qualities, gear, augmentations, weapons, armor, adept powers, foci, and complex forms. Use when adding new items to core-rulebook.json or sourcebook files, or when validating existing catalog entries.
allowed-tools Read, Grep, Glob

Edition Data Author

This skill guides the creation of catalog items for Shadowrun edition data files. All items live in /data/editions/{editionCode}/ JSON files.

Key Files

  • Type definitions: /lib/types/edition.ts
  • SR5 core data: /data/editions/sr5/core-rulebook.json
  • Rating spec types: /lib/types/ratings.ts
  • Quality types: /lib/types/qualities.ts

ID Naming Convention

All IDs use kebab-case with lowercase letters:

combat-sense
ares-predator-v
wired-reflexes
muscle-replacement
control-thoughts

For items with ratings, include the base name only (not the rating):

wired-reflexes     (NOT wired-reflexes-1, wired-reflexes-2)

For items requiring a selection (attribute, skill, limit):

improved-physical-attribute  (with requiresAttribute: true)
improved-ability             (with requiresSkill: true)

Common Patterns

Availability Format

availability: number;           // Base availability value (0-20+)
legality?: "restricted" | "forbidden";  // R or F suffix in books

Cost Patterns

// Fixed cost
cost: 5000;

// Cost with rating (use ratingSpec)
cost: 1000;
ratingSpec: {
  rating: { hasRating: true, maxRating: 6 },
  costScaling: { perRating: true }
}

Page References

page?: number;      // Page number in source book
source?: string;    // "SR5" or book abbreviation

Catalog Item Types

1. Spells

Location: modules.magic.payload.spells.{category}[]

Categories: combat, detection, health, illusion, manipulation

interface SpellCatalogItem {
  id: string;           // kebab-case
  name: string;         // Display name
  category: "combat" | "detection" | "health" | "illusion" | "manipulation";
  type: "mana" | "physical";
  range: "touch" | "LOS" | "LOS(A)" | "self";
  duration: "instant" | "sustained" | "permanent";
  drain: string;        // "F-2", "F", "F+1", etc.
  damage?: string;      // For combat spells: "(F-3)P", "(F)S", etc.
  description: string;
  page?: number;
  source?: string;
}

Example:

{
  "id": "fireball",
  "name": "Fireball",
  "category": "combat",
  "type": "physical",
  "range": "LOS(A)",
  "duration": "instant",
  "drain": "F",
  "damage": "(F)P",
  "description": "Deals Fire damage in an area."
}

2. Qualities

Location: modules.qualities.payload.qualities[]

interface Quality {
  id: string;
  name: string;
  type: "positive" | "negative";
  category: "physical" | "mental" | "social" | "magical" | "mundane" | "metatype";
  cost: number;         // Karma cost (positive for positive qualities)
  maxRating?: number;   // If quality has levels (1-4 typically)
  costPerRating?: boolean;
  metatypeRestrictions?: string[];  // ["human", "elf"]
  prerequisites?: QualityPrerequisites;
  incompatible?: string[];  // IDs of incompatible qualities
  description: string;
  effects?: QualityEffect[];
  source?: SourceReference;
}

Example:

{
  "id": "toughness",
  "name": "Toughness",
  "type": "positive",
  "category": "physical",
  "cost": 9,
  "description": "+1 to Physical damage resistance tests.",
  "effects": [
    {
      "type": "dicePoolModifier",
      "target": "damageResistance",
      "modifier": 1
    }
  ]
}

3. Cyberware

Location: modules.cyberware.payload.cyberware[]

Categories: headware, eyeware, earware, bodyware, cyberlimbs, nervous-system, biomonitors

interface CyberwareCatalogItem {
  id: string;
  name: string;
  category: CyberwareCategory;
  essenceCost: number;          // Base essence cost
  cost: number;                 // Base nuyen cost
  availability: number;
  legality?: "restricted" | "forbidden";

  // For rated items, use ratingSpec (preferred)
  ratingSpec?: CatalogItemRatingSpec;

  // Or legacy properties (deprecated but still work)
  hasRating?: boolean;
  maxRating?: number;
  essencePerRating?: boolean;
  costPerRating?: boolean;

  // Capacity (for cyberlimbs that hold enhancements)
  capacity?: number;            // Capacity this provides
  capacityCost?: number;        // Capacity this consumes (for enhancements)

  // Bonuses
  attributeBonuses?: Record<string, number>;
  initiativeDiceBonus?: number;

  // Descriptions
  description?: string;
  wirelessBonus?: string;

  page?: number;
  source?: string;
}

Example:

{
  "id": "wired-reflexes",
  "name": "Wired Reflexes",
  "category": "nervous-system",
  "essenceCost": 2,
  "cost": 39000,
  "availability": 8,
  "legality": "restricted",
  "ratingSpec": {
    "rating": { "hasRating": true, "minRating": 1, "maxRating": 3 },
    "essenceScaling": { "perRating": true },
    "costScaling": { "values": [39000, 149000, 217000] }
  },
  "initiativeDiceBonus": 1,
  "description": "Hardwired reflexes for faster reaction time.",
  "wirelessBonus": "+1 Initiative Die while wireless enabled."
}

4. Bioware

Location: modules.bioware.payload.bioware[]

Categories: standard, cultured, cosmetic, biosculpting

interface BiowareCatalogItem {
  id: string;
  name: string;
  category: BiowareCategory;
  essenceCost: number;
  cost: number;
  availability: number;
  legality?: "restricted" | "forbidden";

  ratingSpec?: CatalogItemRatingSpec;
  hasRating?: boolean;
  maxRating?: number;

  attributeBonuses?: Record<string, number>;
  description?: string;
  wirelessBonus?: string;

  page?: number;
  source?: string;
}

5. Weapons

Location: modules.gear.payload.weapons.{subcategory}[]

Subcategories: holdout-pistols, light-pistols, heavy-pistols, machine-pistols, smgs, assault-rifles, sniper-rifles, shotguns, lmgs, hmgs, assault-cannons, blades, clubs, exotic-weapons, throwing-weapons, bows, crossbows

interface WeaponCatalogItem {
  id: string;
  name: string;
  subcategory: string;
  damage: string;           // "5P", "8P(f)", "(STR+2)P"
  accuracy: number;
  ap: number;               // Armor Penetration (usually negative)
  mode?: string;            // "SA", "SA/BF", "SA/BF/FA"
  rc?: number;              // Recoil compensation
  ammo?: string;            // "12(c)", "30(c)", "belt"
  cost: number;
  availability: number;
  legality?: "restricted" | "forbidden";
  reach?: number;           // For melee weapons
  concealability?: number;  // Modifier for concealment
  description?: string;
  page?: number;
  source?: string;
}

Example:

{
  "id": "ares-predator-v",
  "name": "Ares Predator V",
  "subcategory": "heavy-pistols",
  "damage": "8P",
  "accuracy": 5,
  "ap": -1,
  "mode": "SA",
  "rc": 0,
  "ammo": "15(c)",
  "cost": 725,
  "availability": 5,
  "legality": "restricted",
  "description": "The iconic sidearm of shadowrunners everywhere."
}

6. Armor

Location: modules.gear.payload.armor[]

interface ArmorCatalogItem {
  id: string;
  name: string;
  armorRating: number;
  capacity: number;         // For armor modifications
  cost: number;
  availability: number;
  legality?: "restricted" | "forbidden";
  encumbrance?: number;     // Modifier to physical tests
  concealability?: number;
  description?: string;
  page?: number;
  source?: string;
}

7. Weapon Modifications

Location: modules.modifications.payload.weaponMods[]

interface WeaponModificationCatalogItem {
  id: string;
  name: string;
  mount?: "top" | "under" | "side" | "barrel" | "stock" | "internal";
  occupiedMounts?: WeaponMountType[];  // Additional mounts used
  isBuiltIn?: boolean;
  compatibleWeapons?: string[];
  incompatibleWeapons?: string[];
  minimumWeaponSize?: "holdout" | "light-pistol" | "heavy-pistol" | "smg" | "rifle" | "heavy";

  cost: number;
  costMultiplier?: number;
  availability: number;
  legality?: "restricted" | "forbidden";

  ratingSpec?: CatalogItemRatingSpec;
  hasRating?: boolean;
  maxRating?: number;

  recoilCompensation?: number;
  accuracyModifier?: number;
  concealabilityModifier?: number;

  description?: string;
  wirelessBonus?: string;
  page?: number;
  source?: string;
}

8. Armor Modifications

Location: modules.modifications.payload.armorMods[]

interface ArmorModificationCatalogItem {
  id: string;
  name: string;
  capacityCost: number;
  noCapacityCost?: boolean;     // If true, doesn't use capacity (bracketed in book)

  ratingSpec?: CatalogItemRatingSpec;
  hasRating?: boolean;
  maxRating?: number;
  capacityPerRating?: boolean;

  cost: number;
  costPerRating?: boolean;
  costMultiplier?: number;
  availability: number;
  availabilityModifier?: number;
  legality?: "restricted" | "forbidden";

  armorBonus?: number;
  requirements?: string[];      // ["full body armor", "helmet"]

  description?: string;
  wirelessBonus?: string;
  page?: number;
  source?: string;
}

9. Adept Powers

Location: modules.adeptPowers.payload.powers[]

interface AdeptPowerCatalogItem {
  id: string;
  name: string;
  cost: number | null;          // Power point cost (null if table-based)
  costType: "fixed" | "perLevel" | "table";
  maxLevel?: number;
  activation?: "free" | "simple" | "complex" | "interrupt";

  // For powers requiring selection
  requiresAttribute?: boolean;
  validAttributes?: string[];
  requiresSkill?: boolean;
  validSkills?: string[];
  requiresLimit?: boolean;
  validLimits?: string[];

  // For table-based costs (like Improved Reflexes)
  levels?: Array<{
    level: number;
    cost: number;
    bonus: string;
  }>;

  // For powers with variants (like Improved Sense)
  variants?: Array<{
    id: string;
    name: string;
    bonus?: string;
  }>;

  description: string;
  page?: number;
  source?: string;
}

10. Foci

Location: modules.foci.payload.foci[]

interface FocusCatalogItem {
  id: string;
  name: string;
  type: "enchanting" | "metamagic" | "power" | "qi" | "spell" | "spirit" | "weapon";
  costMultiplier: number;           // Cost = Force × multiplier
  bondingKarmaMultiplier: number;   // Karma = Force × multiplier
  availability: number;
  legality?: "restricted" | "forbidden";
  description?: string;
  page?: number;
  source?: string;
}

11. Complex Forms

Location: modules.magic.payload.complexForms[]

interface ComplexFormCatalogItem {
  id: string;
  name: string;
  target: "persona" | "device" | "file" | "sprite" | "host" | "self";
  duration: "instant" | "sustained" | "permanent";
  fading: string;           // "L+1", "L-1", "L", etc.
  description: string;
  page?: number;
  source?: string;
}

Unified Ratings Tables (PREFERRED)

For items with ratings, use unified ratings tables - explicit per-rating values that match how source books print data:

interface UnifiedRatingConfig {
  hasRating: true;            // Must be true to enable ratings
  minRating?: number;         // Default: 1
  maxRating: number;          // Maximum rating allowed
  ratings: Record<number, {   // Explicit values for each rating
    cost?: number;            // Nuyen cost at this rating
    availability?: number;    // Availability at this rating
    availabilitySuffix?: "R" | "F";
    essenceCost?: number;     // Essence cost (cyberware/bioware)
    capacity?: number;        // Capacity provided (cyberlimbs, cybereyes)
    capacityCost?: number;    // Capacity consumed (enhancements)
    karmaCost?: number;       // Karma cost (qualities)
    powerPointCost?: number;  // Power point cost (adept powers)
    effects?: {               // Mechanical effects at this rating
      attributeBonuses?: Record<string, number>;
      initiativeDice?: number;
      initiativeScore?: number;
      limitBonus?: number;
      armorBonus?: number;
    };
  }>;
}

Example - Cybereyes (different capacity per rating):

{
  "id": "cybereyes",
  "name": "Cybereyes",
  "category": "eyeware",
  "hasRating": true,
  "minRating": 1,
  "maxRating": 4,
  "ratings": {
    "1": { "cost": 4000, "availability": 3, "essenceCost": 0.2, "capacity": 4 },
    "2": { "cost": 6000, "availability": 6, "essenceCost": 0.3, "capacity": 8 },
    "3": { "cost": 10000, "availability": 9, "essenceCost": 0.4, "capacity": 12 },
    "4": { "cost": 14000, "availability": 12, "essenceCost": 0.5, "capacity": 16 }
  },
  "description": "Replacement eyes with customizable enhancements."
}

Example - Wired Reflexes (non-linear essence/cost):

{
  "id": "wired-reflexes",
  "name": "Wired Reflexes",
  "category": "nervous-system",
  "hasRating": true,
  "minRating": 1,
  "maxRating": 3,
  "ratings": {
    "1": {
      "cost": 39000, "availability": 8, "essenceCost": 2,
      "effects": { "initiativeDice": 1, "initiativeScore": 1 }
    },
    "2": {
      "cost": 149000, "availability": 12, "essenceCost": 3,
      "effects": { "initiativeDice": 2, "initiativeScore": 2 }
    },
    "3": {
      "cost": 217000, "availability": 20, "essenceCost": 5,
      "effects": { "initiativeDice": 3, "initiativeScore": 3 }
    }
  },
  "legality": "restricted",
  "description": "Hardwired reflexes for faster reaction time.",
  "wirelessBonus": "+1 Initiative Die while wireless enabled."
}

Example - Quality with Levels (Toughness):

{
  "id": "toughness",
  "name": "Toughness",
  "type": "positive",
  "category": "physical",
  "hasRating": true,
  "minRating": 1,
  "maxRating": 4,
  "ratings": {
    "1": { "karmaCost": 9 },
    "2": { "karmaCost": 18 },
    "3": { "karmaCost": 27 },
    "4": { "karmaCost": 36 }
  },
  "summary": "+1 to Physical damage resistance tests per level."
}

Why Unified Ratings Tables?

  1. Matches source books - Books print tables, not formulas
  2. Non-linear scaling - Many items don't follow simple formulas
  3. Easier to audit - Direct comparison with source material
  4. Single code path - No special cases for different scaling types
  5. Complete data - All rating-dependent values in one place

Rating Spec (LEGACY FALLBACK)

The ratingSpec format is still supported for backward compatibility, but unified ratings tables are preferred for new data:

interface CatalogItemRatingSpec {
  rating: {
    hasRating: boolean;
    minRating?: number;   // Default: 1
    maxRating: number;
  };
  essenceScaling?: {
    perRating?: boolean;
    values?: number[];    // Specific essence costs per rating
  };
  costScaling?: {
    perRating?: boolean;
    values?: number[];    // Specific costs per rating
  };
  capacityCostScaling?: {
    perRating?: boolean;
    values?: number[];
  };
  attributeBonusScaling?: Record<string, number>;  // Bonus per rating
}

Legacy Example - Muscle Replacement (linear scaling):

{
  "ratingSpec": {
    "rating": { "hasRating": true, "maxRating": 4 },
    "essenceScaling": { "perRating": true },
    "costScaling": { "perRating": true },
    "attributeBonusScaling": { "strength": 1, "agility": 1 }
  }
}

Validation Checklist

When creating new items, verify:

  1. ID is unique within its category
  2. ID follows kebab-case convention
  3. Required fields are present (id, name, category/type-specific fields)
  4. Availability is reasonable (typically 0-20, rarely higher)
  5. Costs are positive numbers in appropriate ranges
  6. Legality is only set when restricted/forbidden (omit for legal items)
  7. Rating specs are consistent:
    • For rated items, prefer unified ratings tables over ratingSpec
    • If hasRating: true, must have maxRating and ratings table
    • Each rating in table should have appropriate cost/availability/essence values
  8. Page references are accurate (if provided)
  9. Descriptions are concise but informative
  10. Unified ratings tables match source book values exactly

Adding to JSON Files

Items are added to arrays within the module payloads:

{
  "modules": {
    "magic": {
      "mergeStrategy": "merge",
      "payload": {
        "spells": {
          "combat": [
            { /* spell 1 */ },
            { /* spell 2 */ }
          ]
        }
      }
    }
  }
}

For sourcebooks, use appropriate merge strategy:

  • merge - Combine with existing data (default)
  • append - Add to arrays without replacing
  • replace - Completely override module