/SKILL.md
# Unity UPM Package Creator Create a Unity Package Manager (UPM) package from existing code, with GitHub Actions for CI/CD and publishing to a private npm registry (Verdaccio or similar). ## Configuration This skill uses configurable settings. When creating a package, check for configuration in this order: 1. **Project config**: `.upm-publish.json` in the package root 2. **User config**: `~/.config/unity-upm/config.json` 3. **Defaults**: Fall back to prompting the user ### Configuration fil
npx skillsauth add matthewmaker/claude-skill-unity-upm-package claude-skill-unity-upm-packageInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Create a Unity Package Manager (UPM) package from existing code, with GitHub Actions for CI/CD and publishing to a private npm registry (Verdaccio or similar).
This skill uses configurable settings. When creating a package, check for configuration in this order:
.upm-publish.json in the package root~/.config/unity-upm/config.json.upm-publish.json){
"registry": {
"url": "https://cicd.entropyreductionservices.com/",
"name": "Entropy Reduction Services",
"scope": "com.entropyreductionservices"
},
"author": {
"name": "Author Name"
},
"github": {
"owner": "MatthewMaker"
}
}
| Field | Description | Example |
|-------|-------------|---------|
| registry.url | npm registry URL for publishing | https://cicd.entropyreductionservices.com/ |
| registry.name | Display name for scoped registry in manifest.json | "Entropy Reduction Services" |
| registry.scope | Package scope prefix | com.entropyreductionservices |
| registry.tokenSecret | GitHub secret name for auth token | VERDACCIO_TOKEN (default) |
| author.name | Default author name for packages | "Matt Maker" |
| github.owner | Default GitHub owner/org for repos | MatthewMaker |
If no config is found, prompt the user for:
package-name/
├── package.json # UPM manifest (required)
├── package.json.meta
├── README.md
├── README.md.meta
├── CHANGELOG.md
├── CHANGELOG.md.meta
├── LICENSE.md
├── LICENSE.md.meta
├── .upm-publish.json # Optional: publishing config
├── .npmignore # Excludes dev files from npm publish
├── .github/
│ └── workflows/
│ ├── ci.yml # Validates package on push/PR
│ └── publish.yml # Publishes to registry on release
├── scripts/
│ └── generate-meta-files.sh # Helper to generate .meta files
├── Editor/ # Editor-only code (optional)
│ ├── Editor.meta
│ ├── PackageName.Editor.asmdef
│ ├── PackageName.Editor.asmdef.meta
│ ├── *.cs
│ └── *.cs.meta
├── Runtime/ # Runtime code (optional)
│ ├── Runtime.meta
│ ├── PackageName.Runtime.asmdef
│ ├── PackageName.Runtime.asmdef.meta
│ ├── *.cs
│ └── *.cs.meta
└── Tests/
└── Editor/
├── Tests.meta
├── Editor.meta
├── PackageName.Tests.asmdef
├── PackageName.Tests.asmdef.meta
├── *Tests.cs
└── *Tests.cs.meta
{
"name": "com.companyname.package-name",
"displayName": "Package Display Name",
"version": "1.0.0",
"unity": "2021.3",
"description": "Package description here.",
"keywords": ["keyword1", "keyword2"],
"author": {
"name": "Author Name"
},
"repository": {
"type": "git",
"url": "[email protected]:Owner/repo-name.git"
},
"license": "MIT",
"publishConfig": {
"registry": "{{REGISTRY_URL}}"
}
}
Package naming convention: com.companyname.package-name (lowercase, hyphens for multi-word names)
Editor assembly (Editor/PackageName.Editor.asmdef):
{
"name": "PackageName.Editor",
"rootNamespace": "CompanyName.PackageName",
"references": [],
"includePlatforms": ["Editor"],
"excludePlatforms": [],
"allowUnsafeCode": false,
"overrideReferences": false,
"precompiledReferences": [],
"autoReferenced": true,
"defineConstraints": [],
"versionDefines": [],
"noEngineReferences": false
}
Runtime assembly (Runtime/PackageName.Runtime.asmdef):
{
"name": "PackageName.Runtime",
"rootNamespace": "CompanyName.PackageName",
"references": [],
"includePlatforms": [],
"excludePlatforms": [],
"allowUnsafeCode": false,
"overrideReferences": false,
"precompiledReferences": [],
"autoReferenced": true,
"defineConstraints": [],
"versionDefines": [],
"noEngineReferences": false
}
Test assembly (Tests/Editor/PackageName.Tests.asmdef):
{
"name": "PackageName.Tests",
"rootNamespace": "CompanyName.PackageName.Tests",
"references": [
"PackageName.Editor",
"UnityEngine.TestRunner",
"UnityEditor.TestRunner"
],
"includePlatforms": ["Editor"],
"excludePlatforms": [],
"allowUnsafeCode": false,
"overrideReferences": true,
"precompiledReferences": ["nunit.framework.dll"],
"autoReferenced": false,
"defineConstraints": ["UNITY_INCLUDE_TESTS"],
"versionDefines": [],
"noEngineReferences": false
}
CRITICAL: Unity requires .meta files for every file and folder in a package. Without them, the package will fail to import.
Folder meta (e.g., Editor.meta):
fileFormatVersion: 2
guid: <32-char-hex-guid>
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
C# script meta (e.g., Script.cs.meta):
fileFormatVersion: 2
guid: <32-char-hex-guid>
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
Assembly definition meta (e.g., *.asmdef.meta):
fileFormatVersion: 2
guid: <32-char-hex-guid>
AssemblyDefinitionImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
Text file meta (e.g., package.json.meta, README.md.meta):
fileFormatVersion: 2
guid: <32-char-hex-guid>
TextScriptImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
GUIDs should be deterministic based on the file path. Use MD5 hash truncated to 32 hex characters:
echo -n "relative/path/to/file" | md5 | cut -c1-32
.github/workflows/ci.yml)name: CI
on:
push:
branches: [main]
paths:
- '**.cs'
- 'package.json'
- '.github/workflows/**'
pull_request:
branches: [main]
jobs:
validate:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Validate package.json
run: |
jq -e '.name' package.json
jq -e '.version' package.json
jq -e '.unity' package.json
echo "package.json validation passed"
- name: Verify package name format
run: |
NAME=$(jq -r '.name' package.json)
if [[ ! "$NAME" =~ ^com\.[a-z]+\.[a-z0-9-]+$ ]]; then
echo "Error: Package name doesn't follow UPM convention"
exit 1
fi
- name: Check CHANGELOG has entry for current version
run: |
VERSION=$(jq -r '.version' package.json)
if grep -q "## \[$VERSION\]" CHANGELOG.md; then
echo "CHANGELOG entry found for version $VERSION"
else
echo "Warning: No CHANGELOG entry for version $VERSION"
fi
- name: Verify meta files exist
run: |
MISSING=0
for file in package.json README.md CHANGELOG.md LICENSE.md; do
if [ -f "$file" ] && [ ! -f "${file}.meta" ]; then
echo "Error: Missing ${file}.meta"
MISSING=1
fi
done
# Check directories and source files...
if [ "$MISSING" -eq 1 ]; then exit 1; fi
.github/workflows/publish.yml)The registry URL is read from package.json's publishConfig.registry field.
name: Publish to Registry
on:
release:
types: [published]
workflow_dispatch:
inputs:
dry_run:
description: 'Dry run (validate without publishing)'
type: boolean
default: false
jobs:
publish:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Get registry URL from package.json
id: registry
run: |
REGISTRY=$(jq -r '.publishConfig.registry // "https://registry.npmjs.org/"' package.json)
echo "url=$REGISTRY" >> $GITHUB_OUTPUT
echo "Publishing to: $REGISTRY"
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
registry-url: ${{ steps.registry.outputs.url }}
- name: Verify version matches tag
if: github.event_name == 'release'
run: |
TAG_VERSION="${{ github.event.release.tag_name }}"
TAG_VERSION="${TAG_VERSION#v}"
PKG_VERSION=$(jq -r '.version' package.json)
if [ "$TAG_VERSION" != "$PKG_VERSION" ]; then
echo "Error: Tag version doesn't match package.json"
exit 1
fi
- name: Publish to registry
if: ${{ !inputs.dry_run }}
run: npm publish
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_REGISTRY_TOKEN }}
Note: The secret name NPM_REGISTRY_TOKEN can be customized. Common names:
VERDACCIO_TOKEN - for Verdaccio registriesNPM_TOKEN - for npmjs.comNPM_REGISTRY_TOKEN - generic namepackage.jsonv1.0.0)gh release create v1.0.0 --title "v1.0.0" --notes "Release notes here"
GitHub:
gh release edit v1.0.0 --notes "⚠️ **DEPRECATED** - Use vX.X.X or later. Reason here."
npm registry:
npm deprecate [email protected] "Reason here - use vX.X.X or later" --registry={{REGISTRY_URL}}
Add to Packages/manifest.json:
{
"scopedRegistries": [
{
"name": "{{REGISTRY_NAME}}",
"url": "{{REGISTRY_URL}}",
"scopes": ["{{SCOPE}}"]
}
],
"dependencies": {
"com.companyname.package-name": "1.0.0"
}
}
When creating a new UPM package:
.upm-publish.json with registry config (or use global config)package.json with correct naming and metadatapublishConfig.registry to package.json.asmdef).meta files for ALL files and foldersREADME.md with installation instructionsCHANGELOG.md with initial version entryLICENSE.md.npmignore to exclude dev files.github/workflows/ci.yml.github/workflows/publish.ymlVERDACCIO_TOKEN)npm view com.company.package --registry={{REGISTRY_URL}}.meta files - run scripts/generate-meta-files.shArgumentException for paths with invalid charactersdevelopment
Maintainer-only workflow for handling GitHub Secret Scanning alerts on OpenClaw. Use when Codex needs to triage, redact, clean up, and resolve secret leakage found in issue comments, issue bodies, PR comments, or other GitHub content.
development
Maintainer workflow for OpenClaw releases, prereleases, changelog release notes, and publish validation. Use when Codex needs to prepare or verify stable or beta release steps, align version naming, assemble release notes, check release auth requirements, or validate publish-time commands and artifacts.
development
Run, watch, debug, and extend OpenClaw QA testing with qa-lab and qa-channel. Use when Codex needs to execute the repo-backed QA suite, inspect live QA artifacts, debug failing scenarios, add new QA scenarios, or explain the OpenClaw QA workflow. Prefer the live OpenAI lane with regular openai/gpt-5.4 in fast mode; do not use gpt-5.4-pro or gpt-5.4-mini unless the user explicitly overrides that policy.
development
End-to-end Parallels smoke, upgrade, and rerun workflow for OpenClaw across macOS, Windows, and Linux guests. Use when Codex needs to run, rerun, debug, or interpret VM-based install, onboarding, gateway smoke tests, latest-release-to-main upgrade checks, fresh snapshot retests, or optional Discord roundtrip verification under Parallels.