Skip to content

Repository files navigation

Omarchy Plugin CI logo

Omarchy Plugin CI

CI Release License: MIT

Your Omarchy plugin works on your machine. Prove its contract in CI.

Omarchy Plugin CI is a secretless GitHub Action and local CLI that checks an Omarchy Quattro plugin's manifest, entry points, structural QML contract, review-worthy capabilities, and isolated configuration lifecycle.

OMARCHY PLUGIN CI

PASS  Manifest schema
PASS  Plugin ID namespace
PASS  Entry points
PASS  QML root contract
PASS  Summon lifecycle
WARN  External network access: api.example.com
PASS  Isolated enable and disable
PASS  Source remained unchanged

Contract level: 3/3

It does not execute plugin code during lifecycle simulation, does not request a GitHub token, and does not claim that a static report proves a plugin is secure.

Community project. Not affiliated with Basecamp or the Omarchy project.

Quick start

Add .github/workflows/omarchy-plugin-ci.yml to an Omarchy plugin repository:

name: Omarchy Plugin CI

on:
  push:
  pull_request:

permissions:
  contents: read

jobs:
  plugin-contract:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v7
      - uses: actions/setup-node@v7
        with:
          node-version: 24
      - uses: duclucky/omarchy-plugin-ci@v0.1.0-beta.1

Push the workflow. The Action writes a complete report into the GitHub Job Summary and stores machine-readable reports in .omarchy-plugin-ci/.

The beta tag is intentionally explicit. For a stricter supply-chain policy, pin the Action to the full commit SHA shown by the release and let Dependabot or Renovate propose updates.

Why this exists

An Omarchy third-party plugin is a Git repository with a manifest.json at its root. Plugin code runs unsandboxed inside the long-lived omarchy-shell process, with the same access as the user's account. The official manual asks users to review repositories before enabling them.

Plugin authors need a repeatable answer to smaller, deterministic questions:

  • Does the manifest match the current Quattro contract?
  • Does every declared kind have a safe entry point?
  • Can a path or symlink escape the plugin directory?
  • Does a summonable component expose the expected lifecycle?
  • What network, process, credential, persistence, or privilege patterns should a human review?
  • Does enable and disable produce a clean shell.json transition?
  • Does the validation process leave the source untouched?

This project turns those questions into versioned evidence. It is a decision aid for maintainers and reviewers, not a security certification.

Evidence levels

The report assigns the highest completed contract level:

Level Evidence What it proves
0 Contract failed The manifest did not reach the official structural baseline
1 Manifest contract Required fields, ID rules, kinds, entry-point paths, and bar placement are valid
2 Structural QML Entry points avoid ShellRoot; summonable components expose or inherit open and close
3 Isolated lifecycle Staging, enable, disable, remove, JSON persistence, and source immutability passed in a temporary HOME

Capability warnings do not lower the contract level. They describe behavior a reviewer should inspect. Use strict mode when project policy requires every warning to be resolved or explicitly suppressed in a future policy file.

What level 3 does not prove

Level 3 is not a real desktop session. It does not prove:

  • visual correctness in Quickshell or Hyprland;
  • correct behavior on every monitor, GPU, driver, or scale factor;
  • correct DBus, PipeWire, network, Bluetooth, or hardware integration;
  • compatibility with every past or future Omarchy release;
  • absence of malicious or vulnerable behavior;
  • that qmllint can resolve Omarchy-specific imports on a generic runner.

A real Omarchy session remains the correct place for rendering, interaction, IPC, hardware, and end-to-end user testing.

Checks

Manifest contract

Hard failures include:

  • missing or invalid manifest.json;
  • unsupported schemaVersion;
  • missing id, name, version, kinds, or entryPoints;
  • empty kinds;
  • unsupported plugin kind;
  • use of the reserved omarchy.* namespace by a third-party plugin;
  • ID containing / or ..;
  • absolute, empty, escaping, or missing entry-point paths;
  • a declared kind without its matching entry point;
  • invalid barWidget.defaultSection.

The supported kind-to-entry-point mapping is:

Manifest kind Entry-point key
bar-widget barWidget
bar bar
panel panel
overlay overlay
menu menu
service service

Best-practice warnings include a non-namespaced ID, non-SemVer version, or missing author and description. These are useful for distribution but are not represented as official hard requirements by the captured registry contract.

Structural QML

The built-in structural checks:

  • reject pragma Singleton on an entry point;
  • reject ShellRoot as an entry-point root;
  • identify the root component;
  • require open(payloadJson) and close() for panel, overlay, and menu entry points, unless they inherit the official Panel component lifecycle.

If qmllint is available, every QML file is also passed to it. A non-zero qmllint result is a warning because generic CI runners may not have the Omarchy and Quickshell import paths. Structural checks still run when qmllint is missing or disabled.

Capability report

The bounded scanner reviews runtime files for high-signal patterns:

Category Examples
network External URLs, curl, wget
process Quickshell Process, Node child processes, Python subprocesses
credentials SSH/GPG paths and credential-like environment names
privilege sudo, pkexec, doas
persistence systemd enable, autostart, crontab
remote-code Download piped into a shell
destructive Recursive or forceful delete commands

Each match includes the file, line, and a bounded evidence excerpt. Findings are warnings because pattern matching can produce false positives and cannot establish intent.

The report deliberately avoids a fake trust score. A clean scan means only that these specific patterns were not detected.

Isolated lifecycle

The lifecycle check creates a temporary HOME and:

  1. Copies the plugin into .config/omarchy/plugins/<id> without executing it.
  2. Reads the staged manifest and verifies the ID.
  3. Applies the documented Quattro shell.json reference for its kind.
  4. Persists and parses the JSON.
  5. Removes every reference during disable.
  6. Removes only the staged plugin directory.
  7. Confirms the source tree digest did not change.
  8. Deletes the temporary sandbox.

This is explicitly a simulation of the documented configuration contract. It does not invoke a live shell IPC endpoint and does not run install hooks or plugin code.

Action inputs

Input Default Description
plugin-path . Repository root or plugin subdirectory
report-dir .omarchy-plugin-ci Destination for report.json and report.md
strict false Turn any warning into a failing verdict
qmllint auto Run qmllint when available; use false to skip

Example for a plugin in a monorepo:

- uses: duclucky/omarchy-plugin-ci@v0.1.0-beta.1
  with:
    plugin-path: plugins/weather
    report-dir: artifacts/weather-contract
    strict: "true"

Action outputs

Output Example Description
verdict pass Selected policy result
contract-level 3 Highest completed evidence level
warnings 2 Warning count
failures 0 Hard contract failure count
report-json /.../report.json Absolute JSON report path
report-markdown /.../report.md Absolute Markdown report path

Consume an output in another step:

- id: omarchy
  uses: duclucky/omarchy-plugin-ci@v0.1.0-beta.1

- if: always()
  run: echo "Contract level ${{ steps.omarchy.outputs.contract-level }}/3"

Local CLI

Requirements:

  • Node.js 20 or newer
  • Git, only for cloning the project
  • Optional: qmllint

Run from a tagged checkout:

git clone --depth 1 --branch v0.1.0-beta.1 \
  https://github.com/duclucky/omarchy-plugin-ci.git
cd omarchy-plugin-ci

node src/cli.mjs --plugin /path/to/plugin

Or install the CLI from the checkout:

npm install --global .
omarchy-plugin-ci --plugin /path/to/plugin

Useful options:

# JSON to stdout and files
omarchy-plugin-ci --plugin . --json

# Fail when any warning exists
omarchy-plugin-ci --plugin . --strict

# Disable optional qmllint execution
omarchy-plugin-ci --plugin . --no-qmllint

# Compact output for scripts
omarchy-plugin-ci --plugin . --quiet

Reports

report.json is intended for automation and future catalog ingestion:

{
  "plugin": {
    "id": "example.focus-timer",
    "version": "1.0.0",
    "kinds": ["bar-widget"]
  },
  "contract": {
    "id": "omarchy-quattro-plugin-v1",
    "level": 3
  },
  "verdict": "pass",
  "counts": {
    "pass": 14,
    "warn": 0,
    "fail": 0,
    "skip": 1
  },
  "capabilities": [],
  "findings": []
}

report.md contains the same evidence in a reviewable table. In GitHub Actions it is appended automatically to $GITHUB_STEP_SUMMARY.

Reports use only the plugin directory name, relative file paths, bounded line evidence, manifest metadata, and check results. The tool does not intentionally include the caller's absolute plugin path in the report.

Exit codes

Code Meaning
0 Checks passed under the selected warning policy
1 Hard failure, or one or more warnings in strict mode
2 Invalid argument, missing plugin directory, or internal execution error

Permissions and privacy

Recommended workflow permissions:

permissions:
  contents: read

The Action:

  • does not require GITHUB_TOKEN;
  • does not request write permissions;
  • does not read repository secrets;
  • does not upload telemetry;
  • does not call an external API;
  • does not execute plugin code in the lifecycle simulation;
  • does not use sudo;
  • writes reports only to the chosen report directory;
  • uses an operating-system temporary directory for the lifecycle sandbox.

The runner may still have network access. Use your organization's normal runner isolation and Action pinning policy.

Contract provenance

The bundled omarchy-quattro-plugin-v1 snapshot was captured on 2026-08-24 from:

See contracts/quattro-v1.json for the machine-readable mapping and docs/CONTRACT.md for the project's contract update policy.

Omarchy changes quickly. A passing report is evidence against this pinned contract snapshot, not a promise about an unknown future branch.

Troubleshooting

qmllint is not installed

This is a SKIP, not a failure. The built-in structural checks still run. Add the Qt package that provides qmllint to the runner if your project wants the additional lint pass, or set qmllint: "false" to make the choice explicit.

qmllint warns about missing imports

Omarchy plugins import Quickshell and Omarchy modules that a generic Ubuntu runner may not know. The tool records the first bounded diagnostic lines as a warning. It does not misrepresent unresolved imports as a runtime failure.

A capability warning matches a comment or fixture

The beta scanner intentionally prefers visible false positives over an opaque trust score. Keep executable fixtures outside the plugin path when possible. Open a rule issue with the minimal case if a pattern should be narrowed.

Level 3 passed but the plugin does not render

Level 3 validates a filesystem and configuration lifecycle, not rendering. Reproduce the issue in a real Omarchy session and attach the generated report so contract failures and runtime failures remain separate.

The plugin uses multiple kinds

Declare every kind and matching entry point. A plugin containing bar-widget is represented by its bar layout entry during lifecycle simulation, matching the shell's enabled-state model. A full bar replaces bar.id. Other plugins use the top-level plugins[] array.

Development

npm ci --ignore-scripts
npm run check
npm test
npm run audit:fixtures

The test suite covers:

  • a valid bar widget reaching level 3;
  • a summonable panel with lifecycle methods;
  • reserved IDs and path traversal failures;
  • capability reporting;
  • strict warning policy;
  • GitHub Action output files;
  • CLI help, version, and exit-code behavior.

GitHub Actions repeats the suite on Ubuntu and in an Arch Linux container, dogfoods the local Action, and tests the clean npm package archive.

Contributing

New hard failures must be deterministic and tied to official Omarchy source or documentation. Capability heuristics remain warnings by default. Every rule needs a minimal fixture and test.

Read CONTRIBUTING.md, then open a focused pull request. Report vulnerabilities through private vulnerability reporting.

Roadmap

  • Contract diff bot for new Omarchy tags and branches
  • Policy file for acknowledged capabilities and scoped exceptions
  • Headless Quickshell experiment with an explicit runtime evidence level
  • SARIF output for code scanning integrations
  • Reusable starter repository for new Omarchy plugins
  • Optional public compatibility index sourced only from signed CI reports

These are roadmap items, not features claimed by the beta.

License

MIT

About

Prove an Omarchy plugin's manifest, QML contract, capabilities, and lifecycle in GitHub Actions.

Topics

Resources

Code of conduct

Contributing

Security policy

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages