modusOps
Versioned, security-prominent pipeline automation for Azure DevOps and GitHub Actions.
Pipelines stay thin: they declare what to run and which version - the real logic lives in SemVer’d PowerShell modules and templates, pulled at runtime. Behaviour changes by promoting a version, not by editing YAML. The build token is bound per-feed so it is structurally incapable of reaching a public source, which makes the supply chain auditable rather than implicit.
See it - a whole operation in nine lines
A scheduled security report, end to end. This is the entire pipeline:
on:
schedule: [{ cron: '0 7 * * 1' }] # Mondays, 07:00
permissions: { contents: read, packages: read }
jobs:
weekly-defender-report:
runs-on: ubuntu-latest
steps:
- uses: my-org/ops-templates/templates/registerModusOpsFeeds@v1 # your templates repo
with: { feeds: '[{ "name": "modusops", "uri": "https://nuget.pkg.github.com/my-org/index.json" }]', token: '$' }
- uses: my-org/ops-templates/templates/installModusOpsModules@v1
with: { modules: '[{ "name": "ModusOps.Toolkit", "repository": "modusops", "version": "2.3.1" }]' }
- shell: pwsh
run: Get-MODefenderIncidents -Since 7d | Send-MOTeamsReport -Title 'Weekly security posture'
The token handling, the Defender and Graph queries, the formatting, the retries - all of it lives in ModusOps.Toolkit 2.3.1, pulled at runtime and pinned by version. To change what the report contains, you promote a version: bump 2.3.1 to 2.4.0. You never touch this file, and the diff that changes production is a one-line version bump someone can actually review.
The alternative - the one this replaces - is a few hundred lines of inline REST calls, token juggling, and JSON parsing living in YAML that nobody wants to own. Same on Azure DevOps: the credential model and thin-operation shape are identical; only the substrate differs.
Cmdlet names above are illustrative - the point is the shape: two pinned templates, one line of intent, all the logic versioned behind the feed.
Two halves, one design
modusOps has two halves that share one design:
modusOps- the PowerShell module (MO*cmdlets) that scaffolds an environment, registers pipelines, and vendors templates into a consumer repo.modusops-templates- the public, versioned template library the tooling pulls from (Azure DevOps includes and GitHub composite actions).
modusOps is built with ModuleForge - the same scaffolding, SemVer, and release-integrity conventions apply here.
Sections
| Section | |
|---|---|
| Getting Started | Install modusOps, scaffold an environment, vendor your first template. |
| Concepts | The architecture, the credential/vault model, and the security stance. |
| Templates | The modusops-templates library: how templates are versioned, vendored, and pinned. |
| Tutorials | End-to-end setups for Azure DevOps and GitHub Actions. |
| Functions | Reference documentation for every exported MO* cmdlet. |
| FAQ | Common questions and troubleshooting. |
The core idea in one picture
flowchart LR
subgraph Consumer repo
P[Thin operation / pipeline\ndeclares what + which version]
T[Vendored template\n+ .modusops.lock]
end
P -->|references| T
T -->|pulls at runtime| M[Version-pinned PowerShell module\nfrom a private feed]
L[modusops-templates\npublic library] -. vendored at author time .-> T
M -. promoted by version .-> P
The pipeline orchestrates; it never carries inline REST calls, parsing, or duplicated auth. Those live in the versioned modules. A new behaviour is a new module version, promoted deliberately.