[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill:01M6F82KSNP2XFX121FZYRK58Y":3,"skill-same:01M6F82KSNP2XFX121FZYRK58Y":78},{"skillNo":4,"name":5,"nameZh":6,"description":7,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":16,"categories":17,"keywords":23,"publishedAt":46,"linkOnly":47,"markdownContent":48,"markdownBody":49,"frontMatter":50,"refName":55,"commitSha":56,"skillDirectory":57,"forksCount":58,"repositoryHtmlUrl":59,"repositoryHomepageUrl":6,"ownerHtmlUrl":60,"ownerBlogUrl":61,"ownerDescription":62,"updatedAt":63,"install":64,"resources":77},"01M6F82KSNP2XFX121FZYRK58Y","maintainx-core-workflow-b",null,"Execute MaintainX secondary workflow: Asset and Location management.\nUse when managing equipment assets, organizing locations\u002Ffacilities,\nbuilding asset hierarchies, and tracking equipment maintenance history.\nTrigger with phrases like \"maintainx asset\", \"maintainx location\",\n\"equipment tracking\", \"asset management\", \"facility hierarchy\".","Dicklesworthstone\u002Fpi_agent_rust","Dicklesworthstone","https:\u002F\u002Favatars.githubusercontent.com\u002Fu\u002F35050222?v=4","01M6CG26AR942CSVMN1M5E3DSE","Jeff Emanuel","01M6CG26EPP71PSHW1VDS71121",1981,"MIT","https:\u002F\u002Fgithub.com\u002FDicklesworthstone\u002Fpi_agent_rust\u002Fblob\u002Fmain\u002Ftests\u002Fext_conformance\u002Fartifacts\u002Fplugins-community\u002Fplugins\u002Fsaas-packs\u002Fmaintainx-pack\u002Fskills\u002Fmaintainx-core-workflow-b\u002FSKILL.md",[18],{"categoryNo":19,"categoryName":20,"taxonomyType":21,"taxonomyTypeDesc":22},"01JBSEEDCAT000000000000023","Skill与智能体开发","SCENARIO","使用场景",[24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45],"core","workflow","maintainx core workflow b","when","hierarchy","with","asset","trigger","io","location","maintenance","use","execute","edit","write","read","curl","grep","history","assets","Bash","npm","2026-11-10 10:12:30",false,"---\nname: maintainx-core-workflow-b\ndescription: |\n  Execute MaintainX secondary workflow: Asset and Location management.\n  Use when managing equipment assets, organizing locations\u002Ffacilities,\n  building asset hierarchies, and tracking equipment maintenance history.\n  Trigger with phrases like \"maintainx asset\", \"maintainx location\",\n  \"equipment tracking\", \"asset management\", \"facility hierarchy\".\nallowed-tools: Read, Write, Edit, Bash(npm:*), Bash(curl:*), Grep\nversion: 1.0.0\nlicense: MIT\nauthor: Jeremy Longshore \u003Cjeremy@intentsolutions.io>\n---\n\n# MaintainX Core Workflow B: Asset & Location Management\n\n## Overview\n\nManage equipment assets and locations in MaintainX. Assets represent equipment that requires maintenance; locations organize your facilities.\n\n## Prerequisites\n\n- Completed `maintainx-install-auth` setup\n- Understanding of asset hierarchy concepts\n- MaintainX account with asset management permissions\n\n## Asset Hierarchy Model\n\n```\nOrganization\n├── Location: Main Plant\n│   ├── Sub-Location: Building A\n│   │   ├── Asset: HVAC Unit A1\n│   │   │   └── Sub-Asset: Compressor\n│   │   └── Asset: Conveyor Line 1\n│   └── Sub-Location: Building B\n│       └── Asset: Boiler System\n└── Location: Warehouse\n    └── Asset: Forklift Fleet\n        ├── Sub-Asset: Forklift #1\n        └── Sub-Asset: Forklift #2\n```\n\n## Instructions\n\n### Step 1: Query Locations\n\n```typescript\n\u002F\u002F src\u002Fworkflows\u002Fasset-location.ts\nimport { MaintainXClient } from '..\u002Fapi\u002Fmaintainx-client';\n\ninterface Location {\n  id: string;\n  name: string;\n  address?: string;\n  parentId?: string;\n  children?: Location[];\n}\n\n\u002F\u002F Get all locations\nasync function getAllLocations(client: MaintainXClient): Promise\u003CLocation[]> {\n  const allLocations: Location[] = [];\n  let cursor: string | undefined;\n\n  do {\n    const response = await client.getLocations({ cursor, limit: 100 });\n    allLocations.push(...response.locations);\n    cursor = response.nextCursor || undefined;\n  } while (cursor);\n\n  return allLocations;\n}\n\n\u002F\u002F Build location hierarchy tree\nfunction buildLocationTree(locations: Location[]): Location[] {\n  const locationMap = new Map\u003Cstring, Location>();\n  const rootLocations: Location[] = [];\n\n  \u002F\u002F First pass: create map\n  locations.forEach(loc => {\n    locationMap.set(loc.id, { ...loc, children: [] });\n  });\n\n  \u002F\u002F Second pass: build tree\n  locations.forEach(loc => {\n    const node = locationMap.get(loc.id)!;\n    if (loc.parentId && locationMap.has(loc.parentId)) {\n      const parent = locationMap.get(loc.parentId)!;\n      parent.children!.push(node);\n    } else {\n      rootLocations.push(node);\n    }\n  });\n\n  return rootLocations;\n}\n\n\u002F\u002F Print location tree\nfunction printLocationTree(locations: Location[], indent = 0) {\n  const prefix = '  '.repeat(indent);\n  locations.forEach(loc => {\n    console.log(`${prefix}├── ${loc.name} (${loc.id})`);\n    if (loc.children && loc.children.length > 0) {\n      printLocationTree(loc.children, indent + 1);\n    }\n  });\n}\n\n\u002F\u002F Usage\nasync function displayLocationHierarchy(client: MaintainXClient) {\n  console.log('=== Location Hierarchy ===\\n');\n  const locations = await getAllLocations(client);\n  const tree = buildLocationTree(locations);\n  printLocationTree(tree);\n}\n```\n\n### Step 2: Query Assets\n\n```typescript\ninterface Asset {\n  id: string;\n  name: string;\n  serialNumber?: string;\n  model?: string;\n  manufacturer?: string;\n  status: 'OPERATIONAL' | 'NON_OPERATIONAL' | 'DECOMMISSIONED';\n  locationId?: string;\n  location?: Location;\n  parentAssetId?: string;\n  customFields?: Record\u003Cstring, any>;\n  createdAt: string;\n  updatedAt: string;\n}\n\n\u002F\u002F Get all assets\nasync function getAllAssets(client: MaintainXClient): Promise\u003CAsset[]> {\n  const allAssets: Asset[] = [];\n  let cursor: string | undefined;\n\n  do {\n    const response = await client.getAssets({ cursor, limit: 100 });\n    allAssets.push(...response.assets);\n    cursor = response.nextCursor || undefined;\n  } while (cursor);\n\n  return allAssets;\n}\n\n\u002F\u002F Get assets by location\nasync function getAssetsByLocation(\n  client: MaintainXClient,\n  locationId: string\n): Promise\u003CAsset[]> {\n  const response = await client.getAssets({ locationId, limit: 100 });\n  return response.assets;\n}\n\n\u002F\u002F Get asset details\nasync function getAssetDetails(\n  client: MaintainXClient,\n  assetId: string\n): Promise\u003CAsset> {\n  return client.getAsset(assetId);\n}\n```\n\n### Step 3: Asset Analysis\n\n```typescript\ninterface AssetAnalysis {\n  totalAssets: number;\n  byStatus: Record\u003Cstring, number>;\n  byLocation: Record\u003Cstring, number>;\n  byManufacturer: Record\u003Cstring, number>;\n  noLocation: Asset[];\n}\n\nasync function analyzeAssets(client: MaintainXClient): Promise\u003CAssetAnalysis> {\n  const assets = await getAllAssets(client);\n\n  const analysis: AssetAnalysis = {\n    totalAssets: assets.length,\n    byStatus: {},\n    byLocation: {},\n    byManufacturer: {},\n    noLocation: [],\n  };\n\n  assets.forEach(asset => {\n    \u002F\u002F Count by status\n    const status = asset.status || 'UNKNOWN';\n    analysis.byStatus[status] = (analysis.byStatus[status] || 0) + 1;\n\n    \u002F\u002F Count by location\n    if (asset.location?.name) {\n      const loc = asset.location.name;\n      analysis.byLocation[loc] = (analysis.byLocation[loc] || 0) + 1;\n    } else {\n      analysis.noLocation.push(asset);\n    }\n\n    \u002F\u002F Count by manufacturer\n    if (asset.manufacturer) {\n      analysis.byManufacturer[asset.manufacturer] =\n        (analysis.byManufacturer[asset.manufacturer] || 0) + 1;\n    }\n  });\n\n  return analysis;\n}\n\n\u002F\u002F Print analysis report\nfunction printAssetReport(analysis: AssetAnalysis) {\n  console.log('=== Asset Analysis Report ===\\n');\n  console.log(`Total Assets: ${analysis.totalAssets}\\n`);\n\n  console.log('By Status:');\n  Object.entries(analysis.byStatus).forEach(([status, count]) => {\n    console.log(`  ${status}: ${count}`);\n  });\n\n  console.log('\\nBy Location:');\n  Object.entries(analysis.byLocation)\n    .sort((a, b) => b[1] - a[1])\n    .slice(0, 10)\n    .forEach(([loc, count]) => {\n      console.log(`  ${loc}: ${count}`);\n    });\n\n  console.log('\\nBy Manufacturer:');\n  Object.entries(analysis.byManufacturer)\n    .sort((a, b) => b[1] - a[1])\n    .slice(0, 10)\n    .forEach(([mfr, count]) => {\n      console.log(`  ${mfr}: ${count}`);\n    });\n\n  if (analysis.noLocation.length > 0) {\n    console.log(`\\nAssets without location: ${analysis.noLocation.length}`);\n  }\n}\n```\n\n### Step 4: Asset Work Order History\n\n```typescript\n\u002F\u002F Get maintenance history for an asset\nasync function getAssetMaintenanceHistory(\n  client: MaintainXClient,\n  assetId: string\n) {\n  const workOrders = await client.getWorkOrders({\n    assetId,\n    limit: 100,\n  });\n\n  \u002F\u002F Analyze work order history\n  const history = {\n    total: workOrders.workOrders.length,\n    completed: workOrders.workOrders.filter(wo => wo.status === 'DONE').length,\n    open: workOrders.workOrders.filter(wo => wo.status === 'OPEN').length,\n    inProgress: workOrders.workOrders.filter(wo => wo.status === 'IN_PROGRESS').length,\n    recentWorkOrders: workOrders.workOrders.slice(0, 5),\n  };\n\n  return history;\n}\n\n\u002F\u002F Generate asset report card\nasync function generateAssetReportCard(\n  client: MaintainXClient,\n  assetId: string\n) {\n  const asset = await getAssetDetails(client, assetId);\n  const history = await getAssetMaintenanceHistory(client, assetId);\n\n  console.log('=== Asset Report Card ===\\n');\n  console.log(`Name: ${asset.name}`);\n  console.log(`ID: ${asset.id}`);\n  console.log(`Status: ${asset.status}`);\n  console.log(`Serial Number: ${asset.serialNumber || 'N\u002FA'}`);\n  console.log(`Manufacturer: ${asset.manufacturer || 'N\u002FA'}`);\n  console.log(`Model: ${asset.model || 'N\u002FA'}`);\n  console.log(`Location: ${asset.location?.name || 'Not assigned'}`);\n  console.log(`\\nMaintenance History:`);\n  console.log(`  Total Work Orders: ${history.total}`);\n  console.log(`  Completed: ${history.completed}`);\n  console.log(`  Open: ${history.open}`);\n  console.log(`  In Progress: ${history.inProgress}`);\n\n  if (history.recentWorkOrders.length > 0) {\n    console.log('\\nRecent Work Orders:');\n    history.recentWorkOrders.forEach(wo => {\n      console.log(`  - ${wo.title} (${wo.status})`);\n    });\n  }\n\n  return { asset, history };\n}\n```\n\n### Step 5: Location-Based Asset View\n\n```typescript\n\u002F\u002F Get assets organized by location\nasync function getAssetsGroupedByLocation(client: MaintainXClient) {\n  const locations = await getAllLocations(client);\n  const assets = await getAllAssets(client);\n\n  const assetsByLocation: Map\u003Cstring, Asset[]> = new Map();\n\n  \u002F\u002F Group assets by location\n  assets.forEach(asset => {\n    const locId = asset.locationId || 'UNASSIGNED';\n    if (!assetsByLocation.has(locId)) {\n      assetsByLocation.set(locId, []);\n    }\n    assetsByLocation.get(locId)!.push(asset);\n  });\n\n  \u002F\u002F Create location map for names\n  const locationMap = new Map(\n    locations.map(loc => [loc.id, loc.name])\n  );\n\n  \u002F\u002F Print organized view\n  console.log('=== Assets by Location ===\\n');\n  assetsByLocation.forEach((locAssets, locId) => {\n    const locName = locationMap.get(locId) || locId;\n    console.log(`\\n${locName} (${locAssets.length} assets):`);\n    locAssets.forEach(asset => {\n      const status = asset.status === 'OPERATIONAL' ? '[OK]' : '[!]';\n      console.log(`  ${status} ${asset.name}`);\n    });\n  });\n\n  return assetsByLocation;\n}\n```\n\n### Step 6: Preventive Maintenance Planning\n\n```typescript\ninterface PMSchedule {\n  assetId: string;\n  assetName: string;\n  lastMaintenanceDate?: Date;\n  nextDueDate: Date;\n  frequency: string; \u002F\u002F e.g., \"30 days\", \"quarterly\"\n  tasks: string[];\n}\n\n\u002F\u002F Plan preventive maintenance based on asset types\nfunction generatePMSchedule(assets: Asset[]): PMSchedule[] {\n  const schedules: PMSchedule[] = [];\n\n  assets.forEach(asset => {\n    \u002F\u002F Skip non-operational assets\n    if (asset.status !== 'OPERATIONAL') return;\n\n    \u002F\u002F Example PM schedules based on asset type (infer from name)\n    const name = asset.name.toLowerCase();\n\n    if (name.includes('hvac') || name.includes('air')) {\n      schedules.push({\n        assetId: asset.id,\n        assetName: asset.name,\n        nextDueDate: new Date(Date.now() + 30 * 24 * 60 * 60 * 1000),\n        frequency: '30 days',\n        tasks: [\n          'Replace air filters',\n          'Check refrigerant levels',\n          'Inspect belts and pulleys',\n          'Clean coils',\n          'Test thermostat',\n        ],\n      });\n    } else if (name.includes('pump')) {\n      schedules.push({\n        assetId: asset.id,\n        assetName: asset.name,\n        nextDueDate: new Date(Date.now() + 90 * 24 * 60 * 60 * 1000),\n        frequency: '90 days',\n        tasks: [\n          'Check seal condition',\n          'Inspect impeller',\n          'Verify flow rates',\n          'Lubricate bearings',\n        ],\n      });\n    } else if (name.includes('conveyor')) {\n      schedules.push({\n        assetId: asset.id,\n        assetName: asset.name,\n        nextDueDate: new Date(Date.now() + 7 * 24 * 60 * 60 * 1000),\n        frequency: '7 days',\n        tasks: [\n          'Inspect belt tension',\n          'Check motor operation',\n          'Lubricate rollers',\n          'Clean sensors',\n        ],\n      });\n    }\n  });\n\n  return schedules;\n}\n\n\u002F\u002F Create work orders from PM schedule\nasync function createPMWorkOrders(\n  client: MaintainXClient,\n  schedules: PMSchedule[]\n) {\n  const created = [];\n\n  for (const schedule of schedules) {\n    const workOrder = await client.createWorkOrder({\n      title: `Scheduled PM - ${schedule.assetName}`,\n      description: `\n## Preventive Maintenance\nFrequency: ${schedule.frequency}\n\n## Tasks\n${schedule.tasks.map(t => `- [ ] ${t}`).join('\\n')}\n      `,\n      priority: 'MEDIUM',\n      assetId: schedule.assetId,\n      dueDate: schedule.nextDueDate.toISOString(),\n    });\n    created.push(workOrder);\n  }\n\n  return created;\n}\n```\n\n## Output\n\n- Complete location hierarchy view\n- Asset inventory analysis\n- Asset maintenance history\n- Location-based asset groupings\n- Preventive maintenance schedules\n\n## Error Handling\n\n| Error | Cause | Solution |\n|-------|-------|----------|\n| 404 Not Found | Invalid asset\u002Flocation ID | Verify ID exists |\n| Empty Results | No data or wrong filter | Check query parameters |\n| Pagination issues | Missing cursor handling | Use pagination helper |\n| Permission denied | Insufficient access | Verify user permissions |\n\n## Asset Status Reference\n\n| Status | Description | Action |\n|--------|-------------|--------|\n| OPERATIONAL | Working normally | Schedule PM |\n| NON_OPERATIONAL | Not functioning | Create repair WO |\n| DECOMMISSIONED | Retired from use | Archive\u002Fremove |\n\n## Resources\n\n- [MaintainX Assets Guide](https:\u002F\u002Fhelp.getmaintainx.com\u002F)\n- [MaintainX Locations](https:\u002F\u002Fhelp.getmaintainx.com\u002F)\n- [API Documentation](https:\u002F\u002Fmaintainx.dev\u002F)\n\n## Next Steps\n\nFor troubleshooting common issues, see `maintainx-common-errors`.\n","# MaintainX Core Workflow B: Asset & Location Management\n\n## Overview\n\nManage equipment assets and locations in MaintainX. Assets represent equipment that requires maintenance; locations organize your facilities.\n\n## Prerequisites\n\n- Completed `maintainx-install-auth` setup\n- Understanding of asset hierarchy concepts\n- MaintainX account with asset management permissions\n\n## Asset Hierarchy Model\n\n```\nOrganization\n├── Location: Main Plant\n│   ├── Sub-Location: Building A\n│   │   ├── Asset: HVAC Unit A1\n│   │   │   └── Sub-Asset: Compressor\n│   │   └── Asset: Conveyor Line 1\n│   └── Sub-Location: Building B\n│       └── Asset: Boiler System\n└── Location: Warehouse\n    └── Asset: Forklift Fleet\n        ├── Sub-Asset: Forklift #1\n        └── Sub-Asset: Forklift #2\n```\n\n## Instructions\n\n### Step 1: Query Locations\n\n```typescript\n\u002F\u002F src\u002Fworkflows\u002Fasset-location.ts\nimport { MaintainXClient } from '..\u002Fapi\u002Fmaintainx-client';\n\ninterface Location {\n  id: string;\n  name: string;\n  address?: string;\n  parentId?: string;\n  children?: Location[];\n}\n\n\u002F\u002F Get all locations\nasync function getAllLocations(client: MaintainXClient): Promise\u003CLocation[]> {\n  const allLocations: Location[] = [];\n  let cursor: string | undefined;\n\n  do {\n    const response = await client.getLocations({ cursor, limit: 100 });\n    allLocations.push(...response.locations);\n    cursor = response.nextCursor || undefined;\n  } while (cursor);\n\n  return allLocations;\n}\n\n\u002F\u002F Build location hierarchy tree\nfunction buildLocationTree(locations: Location[]): Location[] {\n  const locationMap = new Map\u003Cstring, Location>();\n  const rootLocations: Location[] = [];\n\n  \u002F\u002F First pass: create map\n  locations.forEach(loc => {\n    locationMap.set(loc.id, { ...loc, children: [] });\n  });\n\n  \u002F\u002F Second pass: build tree\n  locations.forEach(loc => {\n    const node = locationMap.get(loc.id)!;\n    if (loc.parentId && locationMap.has(loc.parentId)) {\n      const parent = locationMap.get(loc.parentId)!;\n      parent.children!.push(node);\n    } else {\n      rootLocations.push(node);\n    }\n  });\n\n  return rootLocations;\n}\n\n\u002F\u002F Print location tree\nfunction printLocationTree(locations: Location[], indent = 0) {\n  const prefix = '  '.repeat(indent);\n  locations.forEach(loc => {\n    console.log(`${prefix}├── ${loc.name} (${loc.id})`);\n    if (loc.children && loc.children.length > 0) {\n      printLocationTree(loc.children, indent + 1);\n    }\n  });\n}\n\n\u002F\u002F Usage\nasync function displayLocationHierarchy(client: MaintainXClient) {\n  console.log('=== Location Hierarchy ===\\n');\n  const locations = await getAllLocations(client);\n  const tree = buildLocationTree(locations);\n  printLocationTree(tree);\n}\n```\n\n### Step 2: Query Assets\n\n```typescript\ninterface Asset {\n  id: string;\n  name: string;\n  serialNumber?: string;\n  model?: string;\n  manufacturer?: string;\n  status: 'OPERATIONAL' | 'NON_OPERATIONAL' | 'DECOMMISSIONED';\n  locationId?: string;\n  location?: Location;\n  parentAssetId?: string;\n  customFields?: Record\u003Cstring, any>;\n  createdAt: string;\n  updatedAt: string;\n}\n\n\u002F\u002F Get all assets\nasync function getAllAssets(client: MaintainXClient): Promise\u003CAsset[]> {\n  const allAssets: Asset[] = [];\n  let cursor: string | undefined;\n\n  do {\n    const response = await client.getAssets({ cursor, limit: 100 });\n    allAssets.push(...response.assets);\n    cursor = response.nextCursor || undefined;\n  } while (cursor);\n\n  return allAssets;\n}\n\n\u002F\u002F Get assets by location\nasync function getAssetsByLocation(\n  client: MaintainXClient,\n  locationId: string\n): Promise\u003CAsset[]> {\n  const response = await client.getAssets({ locationId, limit: 100 });\n  return response.assets;\n}\n\n\u002F\u002F Get asset details\nasync function getAssetDetails(\n  client: MaintainXClient,\n  assetId: string\n): Promise\u003CAsset> {\n  return client.getAsset(assetId);\n}\n```\n\n### Step 3: Asset Analysis\n\n```typescript\ninterface AssetAnalysis {\n  totalAssets: number;\n  byStatus: Record\u003Cstring, number>;\n  byLocation: Record\u003Cstring, number>;\n  byManufacturer: Record\u003Cstring, number>;\n  noLocation: Asset[];\n}\n\nasync function analyzeAssets(client: MaintainXClient): Promise\u003CAssetAnalysis> {\n  const assets = await getAllAssets(client);\n\n  const analysis: AssetAnalysis = {\n    totalAssets: assets.length,\n    byStatus: {},\n    byLocation: {},\n    byManufacturer: {},\n    noLocation: [],\n  };\n\n  assets.forEach(asset => {\n    \u002F\u002F Count by status\n    const status = asset.status || 'UNKNOWN';\n    analysis.byStatus[status] = (analysis.byStatus[status] || 0) + 1;\n\n    \u002F\u002F Count by location\n    if (asset.location?.name) {\n      const loc = asset.location.name;\n      analysis.byLocation[loc] = (analysis.byLocation[loc] || 0) + 1;\n    } else {\n      analysis.noLocation.push(asset);\n    }\n\n    \u002F\u002F Count by manufacturer\n    if (asset.manufacturer) {\n      analysis.byManufacturer[asset.manufacturer] =\n        (analysis.byManufacturer[asset.manufacturer] || 0) + 1;\n    }\n  });\n\n  return analysis;\n}\n\n\u002F\u002F Print analysis report\nfunction printAssetReport(analysis: AssetAnalysis) {\n  console.log('=== Asset Analysis Report ===\\n');\n  console.log(`Total Assets: ${analysis.totalAssets}\\n`);\n\n  console.log('By Status:');\n  Object.entries(analysis.byStatus).forEach(([status, count]) => {\n    console.log(`  ${status}: ${count}`);\n  });\n\n  console.log('\\nBy Location:');\n  Object.entries(analysis.byLocation)\n    .sort((a, b) => b[1] - a[1])\n    .slice(0, 10)\n    .forEach(([loc, count]) => {\n      console.log(`  ${loc}: ${count}`);\n    });\n\n  console.log('\\nBy Manufacturer:');\n  Object.entries(analysis.byManufacturer)\n    .sort((a, b) => b[1] - a[1])\n    .slice(0, 10)\n    .forEach(([mfr, count]) => {\n      console.log(`  ${mfr}: ${count}`);\n    });\n\n  if (analysis.noLocation.length > 0) {\n    console.log(`\\nAssets without location: ${analysis.noLocation.length}`);\n  }\n}\n```\n\n### Step 4: Asset Work Order History\n\n```typescript\n\u002F\u002F Get maintenance history for an asset\nasync function getAssetMaintenanceHistory(\n  client: MaintainXClient,\n  assetId: string\n) {\n  const workOrders = await client.getWorkOrders({\n    assetId,\n    limit: 100,\n  });\n\n  \u002F\u002F Analyze work order history\n  const history = {\n    total: workOrders.workOrders.length,\n    completed: workOrders.workOrders.filter(wo => wo.status === 'DONE').length,\n    open: workOrders.workOrders.filter(wo => wo.status === 'OPEN').length,\n    inProgress: workOrders.workOrders.filter(wo => wo.status === 'IN_PROGRESS').length,\n    recentWorkOrders: workOrders.workOrders.slice(0, 5),\n  };\n\n  return history;\n}\n\n\u002F\u002F Generate asset report card\nasync function generateAssetReportCard(\n  client: MaintainXClient,\n  assetId: string\n) {\n  const asset = await getAssetDetails(client, assetId);\n  const history = await getAssetMaintenanceHistory(client, assetId);\n\n  console.log('=== Asset Report Card ===\\n');\n  console.log(`Name: ${asset.name}`);\n  console.log(`ID: ${asset.id}`);\n  console.log(`Status: ${asset.status}`);\n  console.log(`Serial Number: ${asset.serialNumber || 'N\u002FA'}`);\n  console.log(`Manufacturer: ${asset.manufacturer || 'N\u002FA'}`);\n  console.log(`Model: ${asset.model || 'N\u002FA'}`);\n  console.log(`Location: ${asset.location?.name || 'Not assigned'}`);\n  console.log(`\\nMaintenance History:`);\n  console.log(`  Total Work Orders: ${history.total}`);\n  console.log(`  Completed: ${history.completed}`);\n  console.log(`  Open: ${history.open}`);\n  console.log(`  In Progress: ${history.inProgress}`);\n\n  if (history.recentWorkOrders.length > 0) {\n    console.log('\\nRecent Work Orders:');\n    history.recentWorkOrders.forEach(wo => {\n      console.log(`  - ${wo.title} (${wo.status})`);\n    });\n  }\n\n  return { asset, history };\n}\n```\n\n### Step 5: Location-Based Asset View\n\n```typescript\n\u002F\u002F Get assets organized by location\nasync function getAssetsGroupedByLocation(client: MaintainXClient) {\n  const locations = await getAllLocations(client);\n  const assets = await getAllAssets(client);\n\n  const assetsByLocation: Map\u003Cstring, Asset[]> = new Map();\n\n  \u002F\u002F Group assets by location\n  assets.forEach(asset => {\n    const locId = asset.locationId || 'UNASSIGNED';\n    if (!assetsByLocation.has(locId)) {\n      assetsByLocation.set(locId, []);\n    }\n    assetsByLocation.get(locId)!.push(asset);\n  });\n\n  \u002F\u002F Create location map for names\n  const locationMap = new Map(\n    locations.map(loc => [loc.id, loc.name])\n  );\n\n  \u002F\u002F Print organized view\n  console.log('=== Assets by Location ===\\n');\n  assetsByLocation.forEach((locAssets, locId) => {\n    const locName = locationMap.get(locId) || locId;\n    console.log(`\\n${locName} (${locAssets.length} assets):`);\n    locAssets.forEach(asset => {\n      const status = asset.status === 'OPERATIONAL' ? '[OK]' : '[!]';\n      console.log(`  ${status} ${asset.name}`);\n    });\n  });\n\n  return assetsByLocation;\n}\n```\n\n### Step 6: Preventive Maintenance Planning\n\n```typescript\ninterface PMSchedule {\n  assetId: string;\n  assetName: string;\n  lastMaintenanceDate?: Date;\n  nextDueDate: Date;\n  frequency: string; \u002F\u002F e.g., \"30 days\", \"quarterly\"\n  tasks: string[];\n}\n\n\u002F\u002F Plan preventive maintenance based on asset types\nfunction generatePMSchedule(assets: Asset[]): PMSchedule[] {\n  const schedules: PMSchedule[] = [];\n\n  assets.forEach(asset => {\n    \u002F\u002F Skip non-operational assets\n    if (asset.status !== 'OPERATIONAL') return;\n\n    \u002F\u002F Example PM schedules based on asset type (infer from name)\n    const name = asset.name.toLowerCase();\n\n    if (name.includes('hvac') || name.includes('air')) {\n      schedules.push({\n        assetId: asset.id,\n        assetName: asset.name,\n        nextDueDate: new Date(Date.now() + 30 * 24 * 60 * 60 * 1000),\n        frequency: '30 days',\n        tasks: [\n          'Replace air filters',\n          'Check refrigerant levels',\n          'Inspect belts and pulleys',\n          'Clean coils',\n          'Test thermostat',\n        ],\n      });\n    } else if (name.includes('pump')) {\n      schedules.push({\n        assetId: asset.id,\n        assetName: asset.name,\n        nextDueDate: new Date(Date.now() + 90 * 24 * 60 * 60 * 1000),\n        frequency: '90 days',\n        tasks: [\n          'Check seal condition',\n          'Inspect impeller',\n          'Verify flow rates',\n          'Lubricate bearings',\n        ],\n      });\n    } else if (name.includes('conveyor')) {\n      schedules.push({\n        assetId: asset.id,\n        assetName: asset.name,\n        nextDueDate: new Date(Date.now() + 7 * 24 * 60 * 60 * 1000),\n        frequency: '7 days',\n        tasks: [\n          'Inspect belt tension',\n          'Check motor operation',\n          'Lubricate rollers',\n          'Clean sensors',\n        ],\n      });\n    }\n  });\n\n  return schedules;\n}\n\n\u002F\u002F Create work orders from PM schedule\nasync function createPMWorkOrders(\n  client: MaintainXClient,\n  schedules: PMSchedule[]\n) {\n  const created = [];\n\n  for (const schedule of schedules) {\n    const workOrder = await client.createWorkOrder({\n      title: `Scheduled PM - ${schedule.assetName}`,\n      description: `\n## Preventive Maintenance\nFrequency: ${schedule.frequency}\n\n## Tasks\n${schedule.tasks.map(t => `- [ ] ${t}`).join('\\n')}\n      `,\n      priority: 'MEDIUM',\n      assetId: schedule.assetId,\n      dueDate: schedule.nextDueDate.toISOString(),\n    });\n    created.push(workOrder);\n  }\n\n  return created;\n}\n```\n\n## Output\n\n- Complete location hierarchy view\n- Asset inventory analysis\n- Asset maintenance history\n- Location-based asset groupings\n- Preventive maintenance schedules\n\n## Error Handling\n\n| Error | Cause | Solution |\n|-------|-------|----------|\n| 404 Not Found | Invalid asset\u002Flocation ID | Verify ID exists |\n| Empty Results | No data or wrong filter | Check query parameters |\n| Pagination issues | Missing cursor handling | Use pagination helper |\n| Permission denied | Insufficient access | Verify user permissions |\n\n## Asset Status Reference\n\n| Status | Description | Action |\n|--------|-------------|--------|\n| OPERATIONAL | Working normally | Schedule PM |\n| NON_OPERATIONAL | Not functioning | Create repair WO |\n| DECOMMISSIONED | Retired from use | Archive\u002Fremove |\n\n## Resources\n\n- [MaintainX Assets Guide](https:\u002F\u002Fhelp.getmaintainx.com\u002F)\n- [MaintainX Locations](https:\u002F\u002Fhelp.getmaintainx.com\u002F)\n- [API Documentation](https:\u002F\u002Fmaintainx.dev\u002F)\n\n## Next Steps\n\nFor troubleshooting common issues, see `maintainx-common-errors`.\n",{"name":5,"author":51,"license":15,"version":52,"description":53,"allowed-tools":54},"Jeremy Longshore \u003Cjeremy@intentsolutions.io>","1.0.0","Execute MaintainX secondary workflow: Asset and Location management.\nUse when managing equipment assets, organizing locations\u002Ffacilities,\nbuilding asset hierarchies, and tracking equipment maintenance history.\nTrigger with phrases like \"maintainx asset\", \"maintainx location\",\n\"equipment tracking\", \"asset management\", \"facility hierarchy\".\n","Read, Write, Edit, Bash(npm:*), Bash(curl:*), Grep","main","90b50ed0778745a80fd5bfb13b1843d45b9e82f7","tests\u002Fext_conformance\u002Fartifacts\u002Fplugins-community\u002Fplugins\u002Fsaas-packs\u002Fmaintainx-pack\u002Fskills\u002Fmaintainx-core-workflow-b",231,"https:\u002F\u002Fgithub.com\u002FDicklesworthstone\u002Fpi_agent_rust","https:\u002F\u002Fgithub.com\u002FDicklesworthstone","https:\u002F\u002Fwww.jeffreyemanuel.com\u002F","Building in NY","2026-11-12 03:15:57",{"source":8,"skillName":5,"commands":65,"prompt":75,"zipAvailable":76},[66,69,72],{"tool":67,"command":68},"npx","npx skills add Dicklesworthstone\u002Fpi_agent_rust --skill maintainx-core-workflow-b",{"tool":70,"command":71},"bunx","bunx skills add Dicklesworthstone\u002Fpi_agent_rust --skill maintainx-core-workflow-b",{"tool":73,"command":74},"pnpm","pnpm dlx skills add Dicklesworthstone\u002Fpi_agent_rust --skill maintainx-core-workflow-b","安装技能，技能地址：https:\u002F\u002Fgithub.com\u002FDicklesworthstone\u002Fpi_agent_rust\u002Fblob\u002Fmain\u002Ftests\u002Fext_conformance\u002Fartifacts\u002Fplugins-community\u002Fplugins\u002Fsaas-packs\u002Fmaintainx-pack\u002Fskills\u002Fmaintainx-core-workflow-b\u002FSKILL.md",true,[],[79,117,141,167,192,214],{"skillNo":80,"name":81,"nameZh":6,"description":82,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":83,"licenseFileUrl":84,"sourceHtmlUrl":85,"categories":86,"keywords":90,"publishedAt":46},"01M6FEGPPK0ZTKCCM0R3E3KS33","web-artifacts-builder","Suite of tools for creating elaborate, multi-component claude.ai HTML artifacts using modern frontend web technologies (React, Tailwind CSS, shadcn\u002Fui). Use for complex artifacts requiring state management, routing, or shadcn\u002Fui components - not for simple single-file HTML\u002FJSX artifacts.","Apache-2.0","https:\u002F\u002Fgithub.com\u002FDicklesworthstone\u002Fpi_agent_rust\u002Fblob\u002Fmain\u002Ftests\u002Fext_conformance\u002Fartifacts\u002Ftemplates-davila7\u002Fcli-tool\u002Fcomponents\u002Fskills\u002Futilities\u002Fweb-artifacts-builder\u002FLICENSE.txt","https:\u002F\u002Fgithub.com\u002FDicklesworthstone\u002Fpi_agent_rust\u002Fblob\u002Fmain\u002Ftests\u002Fext_conformance\u002Fartifacts\u002Ftemplates-davila7\u002Fcli-tool\u002Fcomponents\u002Fskills\u002Futilities\u002Fweb-artifacts-builder\u002FSKILL.md",[87],{"categoryNo":88,"categoryName":89,"taxonomyType":21,"taxonomyTypeDesc":22},"01JBSEEDCAT000000000000009","前端开发",[91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,35,109,110,111,112,113,114,115,116],"web artifacts builder","web","artifacts","artifacts builder","builder","frontend","css","components","react","component","routing","state management","state","shadcn","file","ui","Tools","Tailwind","html","single-file","simple","ui components","multi","for","jsx","suite",{"skillNo":118,"name":119,"nameZh":6,"description":120,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":83,"licenseFileUrl":121,"sourceHtmlUrl":122,"categories":123,"keywords":128,"publishedAt":46},"01M6FEE9VTK1W4GY21AKREJXRG","webapp-testing","Toolkit for interacting with and testing local web applications using Playwright. Supports verifying frontend functionality, debugging UI behavior, capturing browser screenshots, and viewing browser logs.","https:\u002F\u002Fgithub.com\u002FDicklesworthstone\u002Fpi_agent_rust\u002Fblob\u002Fmain\u002Ftests\u002Fext_conformance\u002Fartifacts\u002Ftemplates-davila7\u002Fcli-tool\u002Fcomponents\u002Fskills\u002Fsecurity\u002Fwebapp-testing\u002FLICENSE.txt","https:\u002F\u002Fgithub.com\u002FDicklesworthstone\u002Fpi_agent_rust\u002Fblob\u002Fmain\u002Ftests\u002Fext_conformance\u002Fartifacts\u002Ftemplates-davila7\u002Fcli-tool\u002Fcomponents\u002Fskills\u002Fsecurity\u002Fwebapp-testing\u002FSKILL.md",[124,127],{"categoryNo":125,"categoryName":126,"taxonomyType":21,"taxonomyTypeDesc":22},"01JBSEEDCAT000000000000008","测试与质量",{"categoryNo":88,"categoryName":89,"taxonomyType":21,"taxonomyTypeDesc":22},[129,130,131,96,132,133,92,134,135,136,106,137,138,139,140,29,114],"testing","webapp testing","webapp","screenshots","playwright","debugging","toolkit","browser","logs","applications","behavior","local",{"skillNo":142,"name":143,"nameZh":6,"description":144,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":145,"sourceHtmlUrl":146,"categories":147,"keywords":148,"publishedAt":46},"01M6FE20F7ZTQBFWKF4MPJ2SBX","neuropixels-analysis","Neuropixels neural recording analysis. Load SpikeGLX\u002FOpenEphys data, preprocess, motion correction, Kilosort4 spike sorting, quality metrics, Allen\u002FIBL curation, AI-assisted visual analysis, for Neuropixels 1.0\u002F2.0 extracellular electrophysiology. Use when working with neural recordings, spike sorting, extracellular electrophysiology, or when the user mentions Neuropixels, SpikeGLX, Open Ephys, Kilosort, quality metrics, or unit curation.","https:\u002F\u002Fgithub.com\u002FDicklesworthstone\u002Fpi_agent_rust\u002Fblob\u002Fmain\u002Ftests\u002Fext_conformance\u002Fartifacts\u002Ftemplates-davila7\u002Fcli-tool\u002Fcomponents\u002Fskills\u002Fscientific\u002Fneuropixels-analysis\u002FLICENSE.txt","https:\u002F\u002Fgithub.com\u002FDicklesworthstone\u002Fpi_agent_rust\u002Fblob\u002Fmain\u002Ftests\u002Fext_conformance\u002Fartifacts\u002Ftemplates-davila7\u002Fcli-tool\u002Fcomponents\u002Fskills\u002Fscientific\u002Fneuropixels-analysis\u002FSKILL.md",[],[149,150,151,152,153,154,155,156,35,157,158,159,160,161,162,163,29,164,165,166,114,27],"analysis","neuropixels analysis","spike","metrics","data","open","quality","user","recordings","Neural","motion","visual","quality metrics","unit","sorting","curation","recording","load",{"skillNo":168,"name":169,"nameZh":6,"description":170,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":83,"licenseFileUrl":171,"sourceHtmlUrl":172,"categories":173,"keywords":175,"publishedAt":46},"01M6FDP0PDK6F1GGX395C7625Z","skill-creator","Guide for creating effective skills. This skill should be used when users want to create a new skill (or update an existing skill) that extends Claude's capabilities with specialized knowledge, workflows, or tool integrations.","https:\u002F\u002Fgithub.com\u002FDicklesworthstone\u002Fpi_agent_rust\u002Fblob\u002Fmain\u002Ftests\u002Fext_conformance\u002Fartifacts\u002Ftemplates-davila7\u002Fcli-tool\u002Fcomponents\u002Fskills\u002Fproductivity\u002Fskill-creator\u002FLICENSE.txt","https:\u002F\u002Fgithub.com\u002FDicklesworthstone\u002Fpi_agent_rust\u002Fblob\u002Fmain\u002Ftests\u002Fext_conformance\u002Fartifacts\u002Ftemplates-davila7\u002Fcli-tool\u002Fcomponents\u002Fskills\u002Fproductivity\u002Fskill-creator\u002FSKILL.md",[174],{"categoryNo":19,"categoryName":20,"taxonomyType":21,"taxonomyTypeDesc":22},[176,177,178,179,180,181,182,183,184,185,186,187,188,189,29,114,190,27,191],"skill creator","creator","workflows","create","update","capabilities","knowledge","tool","integrations","specialized","guide","new skill","existing skill","users","Existing","new",{"skillNo":193,"name":194,"nameZh":6,"description":195,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":196,"sourceHtmlUrl":197,"categories":198,"keywords":200,"publishedAt":46},"01M6FDM8Y7VK7NYG9SM7QPA3PW","notebooklm","Use this skill to query your Google NotebookLM notebooks directly from Claude Code for source-grounded, citation-backed answers from Gemini. Browser automation, library management, persistent auth. Drastically reduced hallucinations through document-only responses.","https:\u002F\u002Fgithub.com\u002FDicklesworthstone\u002Fpi_agent_rust\u002Fblob\u002Fmain\u002Ftests\u002Fext_conformance\u002Fartifacts\u002Ftemplates-davila7\u002Fcli-tool\u002Fcomponents\u002Fskills\u002Fproductivity\u002Fnotebooklm\u002FLICENSE","https:\u002F\u002Fgithub.com\u002FDicklesworthstone\u002Fpi_agent_rust\u002Fblob\u002Fmain\u002Ftests\u002Fext_conformance\u002Fartifacts\u002Ftemplates-davila7\u002Fcli-tool\u002Fcomponents\u002Fskills\u002Fproductivity\u002Fnotebooklm\u002FSKILL.md",[199],{"categoryNo":19,"categoryName":20,"taxonomyType":21,"taxonomyTypeDesc":22},[194,201,202,203,204,205,206,136,207,208,35,209,210,211,212,114,213],"google","browser automation","gemini","automation","auth","code","library","management","only","document","query","Citation","source",{"skillNo":215,"name":216,"nameZh":6,"description":217,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":83,"licenseFileUrl":218,"sourceHtmlUrl":219,"categories":220,"keywords":227,"publishedAt":46},"01M6FDHPXE10J3XGTCH5HBHS1M","slack-gif-creator","Knowledge and utilities for creating animated GIFs optimized for Slack. Provides constraints, validation tools, and animation concepts. Use when users request animated GIFs for Slack like \"make me a GIF of X doing Y for Slack.\"","https:\u002F\u002Fgithub.com\u002FDicklesworthstone\u002Fpi_agent_rust\u002Fblob\u002Fmain\u002Ftests\u002Fext_conformance\u002Fartifacts\u002Ftemplates-davila7\u002Fcli-tool\u002Fcomponents\u002Fskills\u002Fenterprise-communication\u002Fslack-gif-creator\u002FLICENSE.txt","https:\u002F\u002Fgithub.com\u002FDicklesworthstone\u002Fpi_agent_rust\u002Fblob\u002Fmain\u002Ftests\u002Fext_conformance\u002Fartifacts\u002Ftemplates-davila7\u002Fcli-tool\u002Fcomponents\u002Fskills\u002Fenterprise-communication\u002Fslack-gif-creator\u002FSKILL.md",[221,224],{"categoryNo":222,"categoryName":223,"taxonomyType":21,"taxonomyTypeDesc":22},"01JBSEEDCAT000000000000005","邮件与沟通",{"categoryNo":225,"categoryName":226,"taxonomyType":21,"taxonomyTypeDesc":22},"01JBSEEDCAT000000000000016","图像与多媒体",[228,229,230,177,231,107,232,233,182,35,234,189,235,236,237,114,238,27],"slack gif creator","slack","gif","validation","constraints","Animation","me","make","Utilities","concepts","request"]