Development Guide¶
This page describes how the Omarchy Tweaker development environment is set up, how the quality tooling is configured, and how to work on the project day to day.
Omarchy Tweaker is a terminal-first, Python 3.13+ toolkit for customizing and automating personal Omarchy (Arch Linux) installations. The repository is currently in the scaffolding stage: the CLI entry point and the full tooling pipeline exist, while feature modules are still being built.
Quick Start¶
For the impatient, a complete local setup looks like this:
git clone https://github.com/Armoghans-Organization/Omarchy-Tweaker.git
cd Omarchy-Tweaker
uv sync --all-groups
uv run pre-commit install --install-hooks
uv run poe check
If every task passes, the environment is ready.
Requirements¶
| Requirement | Version | Notes |
|---|---|---|
| Linux | Any modern distribution | Targets Omarchy / Arch Linux. |
| Python | 3.13 or newer | Pinned to 3.13 in .python-version. |
| uv | Latest | Dependency management and task execution. |
| Git | Latest | Version control and Git hooks. |
uv can install and manage the required Python interpreter, so a system Python 3.13 is
not strictly necessary.
Optional Tools¶
These are not required for development but are used by the developer workspace helpers:
- Zellij — terminal multiplexer used by
session.sh/session.kdl. - gum — styled shell output used by
session.sh.
Setup¶
1. Clone the repository¶
2. Install dependencies¶
Dependency groups
--all-groups installs the runtime, development (dev), and documentation (docs)
dependency groups. CI uses uv sync --locked so the lockfile is never silently
modified.
The dev group provides the full quality toolchain:
ruff— linting and formatting.mypy— strict static typing.pytest,pytest-mock,pytest-cov,pytest-rich— testing and coverage.bandit— Python security analysis.codespell— spelling checks.pre-commit— Git hook management.poethepoet— task runner.
The docs group provides:
zensical— documentation site generator.git-cliff— changelog and release-note generation.
3. Install Git hooks¶
The project installs three hook types by default (see
.pre-commit-config.yaml):
pre-commit— fast checks on staged files.commit-msg— Conventional Commits validation.pre-push— full-project type checking and test suite.
4. Verify the setup¶
This runs linting, formatting checks, type checking, and the test suite.
5. Optional: launch the developer workspace¶
This creates a dedicated Zellij session using session.kdl.
Project Layout¶
Omarchy-Tweaker/
├── .github/
│ ├── templates/ # Git Cliff changelog / release-note templates
│ └── workflows/ # ci.yml, docs.yml, release.yml
├── docs/ # Zensical documentation sources
│ ├── changelog.md # GENERATED — do not edit by hand
│ ├── development.md # This page
│ ├── index.md
│ ├── release-notes.md # GENERATED — do not edit by hand
│ ├── overrides/ # Theme overrides
│ ├── stylesheets/ # Custom CSS
│ ├── favicons/ · images/ # Static assets
├── src/omarchy_tweaker/
│ └── __init__.py # CLI entry point (currently a welcome message)
├── tests/
│ ├── __init__.py
│ └── test_main.py # CLI smoke test
├── .gitignore
├── .pre-commit-config.yaml # Git hook definitions
├── .python-version # Pinned interpreter (3.13)
├── AGENTS.md # AI agent development guidelines
├── cliff.toml # Git Cliff configuration
├── CODE_OF_CONDUCT.md
├── CONTRIBUTING.md
├── LICENSE
├── pyproject.toml # Project metadata, tooling, and Poe tasks
├── Readme.md
├── SECURITY.md
├── session.kdl / session.sh # Optional Zellij developer workspace
├── SUPPORT.md
├── uv.lock # Locked dependency graph
└── zensical.toml # Documentation site configuration
Generated Artifacts¶
The following are produced by tasks and must never be committed:
dist/,build/— package builds.site/— compiled documentation..cache/,.pytest_cache/,.mypy_cache/,.ruff_cache/..coverage,htmlcov/.bandit-report.json.docs/changelog.md,docs/release-notes.md— regenerated from Git history.
When feature modules are added, they are expected to follow the target structure under
src/omarchy_tweaker/ (for example cli/, core/, and models/). That structure does
not exist yet.
Toolchain and Configuration¶
All tooling is configured in pyproject.toml.
Ruff — Linting and Formatting¶
| Setting | Value |
|---|---|
| Line length | 100 |
| Target version | py313 |
| Format quote style | double |
| Enabled rule families | E, F, I, UP, B, SIM, PERF |
| Ignored rule | B008 (function call in default argument) |
| First-party import | omarchy_tweaker |
| Tests-only ignore | E501 (long lines) under tests/**/*.py |
Do not add inline suppressions merely to silence a warning. If a suppression is genuinely required, it must have a clear justification.
Mypy — Strict Typing¶
| Setting | Value |
|---|---|
| Mode | strict = true |
| Checked paths | src, tests |
| Python version | 3.13 |
| Extras | pretty, show_error_codes, warn_unused_configs, warn_redundant_casts, warn_unused_ignores |
All public functions, methods, and modules should carry complete type annotations. Do not weaken strict mode to make code pass; resolve the underlying typing issue instead.
Bandit — Security Analysis¶
| Setting | Value |
|---|---|
| Target | src |
| Excluded directories | tests, .venv, build, dist |
| Severity threshold | LOW |
| Confidence threshold | MEDIUM |
| Skipped checks | none |
Pytest and Coverage¶
| Setting | Value |
|---|---|
| Test paths | tests |
| File pattern | test_*.py |
| Default flags | -ra |
| Coverage source | omarchy_tweaker |
| Branch coverage | enabled |
| Excluded from coverage | tests, pragma: no cover, __repr__, TYPE_CHECKING blocks |
External commands, package-manager calls, privileged operations, filesystem writes, and service changes must be mocked. Tests must never modify the host system.
Poe the Poet — Task Runner¶
Tasks are defined under [tool.poe.tasks] in pyproject.toml.
Task Runner¶
Run any task with uv run poe <task>.
Linting¶
| Command | Purpose |
|---|---|
uv run poe lint |
Check code with Ruff. |
uv run poe lint-fix |
Apply supported Ruff fixes automatically. |
Formatting¶
| Command | Purpose |
|---|---|
uv run poe format |
Format Python files with Ruff. |
uv run poe format-check |
Verify formatting without modifying files. |
Type Checking¶
| Command | Purpose |
|---|---|
uv run poe typecheck |
Run strict Mypy checks. |
Testing and Coverage¶
| Command | Purpose |
|---|---|
uv run poe test |
Run the test suite verbosely (pytest -v). |
uv run poe coverage |
Run tests with a terminal coverage report. |
Security¶
| Command | Purpose |
|---|---|
uv run poe security |
Scan src with Bandit using project thresholds. |
uv run poe security-report |
Write a JSON Bandit report to bandit-report.json. |
Changelog and Release Notes¶
| Command | Purpose |
|---|---|
uv run poe changelog |
Generate docs/changelog.md from Git history. |
uv run poe changelog-preview |
Preview unreleased changelog entries. |
uv run poe release-notes |
Generate docs/release-notes.md for the latest release. |
uv run poe release-notes-preview |
Preview unreleased release notes. |
uv run poe docs-generate |
Run changelog and release-notes together. |
Documentation¶
| Command | Purpose |
|---|---|
uv run poe docs |
Generate docs content and start the live server. |
uv run poe docs-serve |
Serve the site with live reload. |
uv run poe docs-build |
Generate docs content and build the site. |
uv run poe docs-compile |
Build the site with strict validation. |
uv run poe docs-deploy |
Generate docs content and deploy to GitHub Pages. |
uv run poe docs-publish |
Deploy via Zensical's gh-deploy. |
Building and Cleanup¶
| Command | Purpose |
|---|---|
uv run poe build |
Build the sdist and wheel with uv build. |
uv run poe clean |
Remove dist, build, .coverage, site, and generated docs. |
Combined Checks¶
| Command | Purpose |
|---|---|
uv run poe check |
lint + format-check + typecheck + test. |
uv run poe pre-commit |
Same four checks, intended for local pre-commit use. |
uv run poe ci |
lint + format-check + typecheck + coverage + docs-build + build. |
poe pre-commit is not the Git hook runner
uv run poe pre-commit runs the same quality checks as poe check. To execute the
actual Git hooks, use uv run pre-commit run --all-files.
Git Hooks (pre-commit)¶
The repository uses pre-commit to enforce quality gates before
code reaches the remote. Local hooks invoke tools through uv run --locked so the
environment matches the lockfile exactly.
Hook Stages¶
| Stage | Hooks | Purpose |
|---|---|---|
pre-commit |
Git hygiene, file validation, Ruff lint/format, Bandit, Codespell | Fast checks on staged files. |
commit-msg |
Conventional Commits | Message validation. |
pre-push |
Mypy, Pytest | Full-project verification. |
Hook Categories¶
| Category | Hooks |
|---|---|
[GIT] |
trailing whitespace, EOF newline, LF endings, merge conflicts, large files, case conflicts. |
[CONFIG] |
TOML, YAML, JSON, and XML validation. |
[PYTHON] |
syntax validation, debugger-statement detection. |
[SECURITY] |
private-key detection, Bandit. |
[SCRIPTS] |
shebang and executable-permission validation. |
[QUALITY] |
Ruff linting and formatting. |
[DOCS] |
Codespell spelling validation. |
[COMMIT] |
Conventional Commits enforcement. |
[TYPES] |
Mypy strict type checking. |
[TESTS] |
Pytest full suite. |
Most hooks are configured with verbose: true, so the terminal shows exactly which hook
is running, which files it touched, and the full tool output.
Common Commands¶
| Command | Purpose |
|---|---|
uv run pre-commit install --install-hooks |
Install all configured hook types and environments. |
uv run pre-commit uninstall |
Remove installed hooks. |
uv run pre-commit run |
Run hooks against staged files. |
uv run pre-commit run --all-files |
Run every hook against every file. |
uv run pre-commit run <hook-id> --all-files |
Run a single hook (for example ruff). |
uv run pre-commit autoupdate |
Update hook repositories to their latest revisions. |
uv run pre-commit clean |
Clear cached hook environments. |
To skip a specific hook for one run:
Hooks that report (no files to check)Skipped
The JSON and XML validators skip automatically when the repository contains no matching files. This is expected and is not an error.
Daily Development Workflow¶
A typical change follows this loop:
- Create a branch (only with explicit authorization for AI agents — see
AGENTS.md). - Make a focused change with tests and documentation updates.
- Run the fast feedback loop:
- Run the full gate before committing:
- Commit using a Conventional Commit message.
- Push (the
pre-pushhooks run Mypy and Pytest automatically).
For documentation, packaging, or pipeline changes, run the full pipeline instead:
Testing¶
Tests live under tests/ and use Pytest with Pytest-Mock and Pytest-Cov.
Running Tests¶
Run a single test or file directly:
uv run pytest tests/test_main.py -v
uv run pytest tests/test_main.py::test_main_prints_welcome_message -v
uv run pytest -k "welcome" -v
Guidelines¶
- Test public behavior, invalid input, error conditions, and edge cases.
- Name tests descriptively, for example
test_install_package_handles_command_failure. - Use
pytest-mock(mocker) to isolate external dependencies. - Use
tmp_pathfor filesystem work instead of touching real user directories. - Never install, remove, or modify real packages or system services during tests.
- Treat coverage as a signal, not a target: prioritize critical paths and failure handling over an arbitrary percentage.
Current Coverage¶
The suite currently contains a single CLI smoke test (tests/test_main.py). External
system operations must be mocked as feature modules are introduced.
Commit Message Conventions¶
Commit messages are validated by the conventional-pre-commit hook in strict mode.
Format:
Allowed types: feat, fix, docs, style, refactor, perf, test, build, ci,
chore, and revert. The header is limited to 100 characters.
Examples:
feat: add package management commands
fix: handle missing configuration files
refactor(core): separate system operations from the CLI
docs: improve installation documentation
test: add package manager tests
chore: update development dependencies
Indicator a breaking change with ! after the type or scope, and/or a BREAKING CHANGE:
footer:
Keep messages descriptive enough for git-cliff to build meaningful changelogs.
Documentation¶
Documentation is built with Zensical and configured in
zensical.toml. The site navigation currently exposes:
- Home →
index.md - Development →
development.md - Changelog →
changelog.md(generated) - Release Notes →
release-notes.md(generated)
Local Preview¶
This starts a live-reload server. To build the site without serving it:
docs-build regenerates the changelog and release notes before compiling the site with
--clean --strict, so broken links and invalid content fail the build.
Editing Documentation¶
- Source pages live in
docs/. - Theme overrides live in
docs/overrides/. - Custom styling lives in
docs/stylesheets/extra.css. - Never edit
docs/changelog.mdordocs/release-notes.mdby hand; they are generated from Git history. - Keep documentation accurate. Do not document features that are not implemented.
Deployment¶
The Documentation workflow (.github/workflows/docs.yml) builds and deploys the site to
GitHub Pages on pushes to main and on v* tags. It uses uv run --frozen --group docs
to guarantee a reproducible build.
CI/CD Pipeline¶
ci.yml — Continuous Integration¶
Triggered on pushes and pull requests to main, and manually via workflow_dispatch.
| Job | What it does |
|---|---|
quality |
Runs on Python 3.13 and 3.14; installs with uv sync --locked; runs lint, format-check, typecheck, and coverage. |
docs |
Installs the docs group and runs poe docs-build. |
build |
Depends on quality and docs; runs uv build, validates with twine check, and uploads the distributions. |
docs.yml — Documentation Deployment¶
Pushes to main or v* tags build the site and publish it to GitHub Pages.
release.yml — Release Automation¶
Triggered by tags matching v*. It:
- Verifies that the Git tag matches the
pyproject.tomlversion. - Builds the sdist and wheel.
- Validates artifacts with
twine check. - Generates
RELEASE_NOTES.md,CHANGELOG.md, and the documentation copies withgit-cliff. - Creates or updates the GitHub Release and uploads the artifacts.
Release Process¶
The project follows Semantic Versioning (MAJOR.MINOR.PATCH).
- Update
versioninpyproject.toml. - Regenerate and review the changelog and release notes:
- Run the full pipeline:
- Commit and push the version bump.
- Create and push a tag that matches the version exactly:
The release.yml workflow rejects a tag whose version does not match pyproject.toml.
Troubleshooting¶
uv.lock is out of date¶
Symptom: uv run --locked fails, or pre-commit hooks error while resolving dependencies.
Commit the updated uv.lock when dependency changes require it. Do not edit the lockfile
manually.
A pre-commit hook fails¶
Inspect the output, fix the issue, re-stage, and commit again. Use SKIP=<hook-id> only
when a hook is genuinely not applicable.
Hooks report (no files to check)Skipped¶
Expected for validators whose file types are absent (for example JSON or XML). No action is needed.
Mypy strict errors appear during push¶
The pre-push stage runs full-project Mypy. Fix the annotations rather than adding
# type: ignore. Verify locally with uv run poe typecheck.
Bandit generates bandit-report.json¶
That file is a generated artifact and is excluded from hooks and Git. Remove it with
uv run poe clean or delete it manually.
Documentation build fails on missing generated files¶
Run uv run poe docs-generate (or uv run poe docs-build, which does it automatically)
before building.
Contribution Checklist¶
Before opening a pull request, confirm that:
- The change is focused and does not include unrelated refactoring.
- Tests cover new behavior and failure paths.
- Documentation is updated where behavior changed.
-
uv run poe checkpasses. -
uv run poe cipasses for packaging, docs, or pipeline changes. - Commit messages follow Conventional Commits.
- No generated artifacts, secrets, or virtual environments are staged.
Additional contribution expectations are described in CONTRIBUTING.md and AGENTS.md.
Command Cheat Sheet¶
| Goal | Command |
|---|---|
| Install everything | uv sync --all-groups |
| Install Git hooks | uv run pre-commit install --install-hooks |
| Lint and auto-fix | uv run poe lint-fix |
| Format | uv run poe format |
| Type check | uv run poe typecheck |
| Run tests | uv run poe test |
| Coverage | uv run poe coverage |
| Security scan | uv run poe security |
| Full local gate | uv run poe check |
| Full pipeline | uv run poe ci |
| Build package | uv run poe build |
| Serve docs | uv run poe docs-serve |
| Build docs | uv run poe docs-build |
| Run all hooks | uv run pre-commit run --all-files |
| Clean artifacts | uv run poe clean |