Creating a New PSI Tool
Decision guide for building and distributing new tools at PSI. Covers where to host it, how to deploy it, and which distribution channel to use.
Where Does My Tool Go?
What are you building?
│
├── Desktop app used by everyone (shop floor, office)
│ └── ProApps pipeline → DFS share → Pro Update
│ See: [[onboard-new-app]]
│
├── Web application (browser-based)
│ └── Azure App Service or Static Web App
│ See: [[deploy-to-azure]]
│
├── CLI / developer tool (command-line)
│ └── PSI WinGet Source → winget install PSI.MyTool
│ See below ↓
│
├── API / backend service
│ └── Azure App Service (container or zip deploy)
│ See: [[deploy-to-azure]]
│
└── Windows Service (runs in background)
└── ProApps pipeline (service variant)
See: [[onboard-new-app#if-your-app-is-a-windows-service|If Your App Is a Windows Service]]
Quick rule: If a developer types it in a terminal, it goes to WinGet. If an employee clicks an icon, it goes to Pro Update. If it runs in a browser, it goes to Azure.
Creating a CLI Tool for PSI WinGet
Step 1: Create the GHE Repo
Create a new repo at progressivesurface.ghe.com/ProgressiveSurface/your-tool-name.
Step 2: Write Your Tool
Python tools — single script with a version:
#!/usr/bin/env python3
"""My PSI Tool — does the thing."""
__version__ = "1.0.0"
# Your code here....NET tools — set version in .csproj:
<PropertyGroup>
<Version>1.0.0</Version>
</PropertyGroup>Step 3: Choose Your Package ID
Follow the naming convention: PSI.<ToolName>
| Example | Package ID |
|---|---|
| Claude Session Manager | PSI.CSM |
| Developer Setup | PSI.DevSetup |
| Export CLI | PSI.ExportCLI |
| PLC Runner | PSI.PLCRunner |
Step 4: Add the Publish Workflow
Copy the appropriate template from the psi-winget-source repo to .github/workflows/release.yml in your repo.
Templates available:
release-python.yml— Python tools (PyInstaller)release-dotnet.yml— .NET tools (self-contained publish)
Only 5 values to change at the top of the file:
env:
PACKAGE_ID: "PSI.MyTool" # WinGet package identifier
PACKAGE_NAME: "My Tool" # Display name
DESCRIPTION: "What this tool does" # Short description
SCRIPT_FILE: "mytool.py" # Main script (Python) or PROJECT_PATH (dotnet)
EXE_NAME: "mytool" # Command name users will typeStep 5: Push and Release
git add .
git commit -m "Initial tool implementation"
git push origin mainThe workflow:
- Reads
__version__(Python) or<Version>(.NET) from your code - Checks if that version is already published — skips if so
- Builds the executable
- Uploads to Azure Blob Storage
- Registers in the PSI WinGet Source API
- Users can now
winget install PSI.MyTool --source PSI
To release a new version: bump the version in your code and push.
__version__ = "1.1.0" # Was 1.0.0That’s it. No manual steps.
How It Works Under the Hood
Developer pushes to main (with version bump)
│
└──► GitHub Actions (ps-gr-runner)
│
├── Read version from code
├── Check if already published (skip if so)
├── Build executable (PyInstaller or dotnet publish)
├── Compute SHA256
├── Upload zip to Azure Blob Storage (psiwingetpkgs)
└── Register version via PSI WinGet Source API
│
└──► packages.progressivesurface.com/api/admin/packages/{id}/versions
│
└──► Azure SQL (persistent package registry)
Users:
winget upgrade --source PSI → sees new version → installs
What the templates handle automatically:
- Creating the package in WinGet if it doesn’t exist yet (first publish)
- Skipping if the version is already published (idempotent)
- Building, packaging, hashing, uploading, and registering
- Managed identity auth to Azure (no secrets to configure)
Distribution Channel Comparison
| PSI WinGet | Pro Update (DFS) | Azure App Service | |
|---|---|---|---|
| For | CLI/dev tools | Desktop apps (all employees) | Web apps |
| Install | winget install PSI.X | Pro Update client | Browser |
| Update | winget upgrade or app self-check | Auto-poll every 5min | Auto-deploy on push |
| Build | PyInstaller / dotnet publish | MSBuild | npm build / dotnet publish |
| Storage | Azure Blob + WinGet API | DFS network share | App Service |
| Auth | Intune pushes source | AD username in PSApplications.txt | Entra ID / MSAL |
| Audience | Developers (5-10) | All employees (200+) | Internal users |
Checklist
- Repo created on GHE
- Tool has
__version__(Python) or<Version>(.NET) in the code - Workflow file copied from template and 5 env vars updated
- First push to main — workflow runs and publishes v1.0.0
- Verify:
winget search --source PSI PSI.YourTool - Verify:
winget install PSI.YourTool --source PSI - Update this wiki if adding a new tool to the Available Packages list
Available Packages
| Package ID | Name | Repo | Description |
|---|---|---|---|
PSI.CSM | Claude Session Manager | claude-session-manager | TUI for browsing/resuming Claude Code sessions (csm); also ships the Claude Work Board (csm board) — a live local web app showing every project (sessions ↔ git ↔ GHE Issues/PRs ↔ Azure DevOps). One-click ”▶ start Claude” on any issue launches an interactive claude --remote-control session and opens claude.ai/code/session_<id> in a new tab so you can drive it from any device. Alt-click for unattended claude -p |
Update this table when adding new packages.
Related Pages
- winget-source — WinGet source architecture, admin UI, troubleshooting
- onboard-new-app — ProApps onboarding (desktop apps for all employees)
- deploy-to-azure — Web app deployment patterns
- dev-setup — Developer machine setup
Last updated: April 2026