dotmaster
Declarative project configuration, kept in sync.
Answer a few questions once, get
.gitignore, linting, formatting, Docker, CI, and more — all generated together, recorded in onedotmaster.yaml, and continuously verifiable withdotmaster check.
Status: beta. The output-correctness and safety issues from earlier 0.2.x releases are fixed and covered by tests (see CHANGELOG), but the plugin API and config schema may still change before 1.0.
Why dotmaster and not a scaffolder
Cookiecutter, Copier, and create-* tools generate a new project.
dotmaster generates and maintains the configuration layer of a project
that may already exist — and, unlike a one-shot generator, it remembers what
it wrote:
dotmaster init # answer questions once → dotmaster.yaml + generated files
dotmaster check # in CI: fail the build if the repo has drifted from dotmaster.yaml
dotmaster sync # bring the repo back in line
dotmaster diff # see what sync would change, before it changes anything
Edit dotmaster.yaml by hand, or an org-wide preset changes — either way,
sync converges the repo, your own edits to generated files are preserved
where they can be merged, and files you've genuinely modified are reported as
conflicts rather than silently overwritten.
Installation
pipx install dotmaster
# or: uvx dotmaster init
Quick start
cd my-project
dotmaster init
Non-interactive (CI, scripts, agents):
dotmaster init --preset backend_api --yes
dotmaster init --yes --set stack.languages=python,typescript --set infrastructure.docker=true
Commands
| Command | Description |
|---|---|
dotmaster init |
Run the wizard (or --yes/--set) and generate dotfiles |
dotmaster sync |
Regenerate from dotmaster.yaml; safe to run repeatedly |
dotmaster diff |
Show what sync would change, without changing anything |
dotmaster check |
Exit non-zero if the project has drifted — for CI |
dotmaster add <plugin> |
Add or regenerate one plugin's files |
dotmaster remove <plugin> |
Delete a plugin's generated files |
dotmaster restore [--list] |
Restore files from a pre-generation backup |
dotmaster list |
Show available plugins (and which are active) |
dotmaster profile list|show|apply |
Inspect or apply a preset profile |
dotmaster validate |
Check dotmaster.yaml for schema and consistency errors |
dotmaster doctor |
Detected stack, installed tools, plugin health, drift |
Every write command supports --dry-run, --force (overwrite files you've
edited since they were generated), and --output <dir>.
How regeneration actually works
- Each active plugin's
plan()describes the files it wants, as data — it never touches disk. - The engine resolves that against what's on disk and against
.dotmaster/state.json(dotmaster's private record of what it last generated and its content hash — not meant to be committed). - If you haven't touched a file, it's regenerated freely. If you have,
it's reported as a conflict and left alone unless you pass
--force. Structured formats (JSON/YAML/TOML) merge instead of conflicting: your keys always win, new keys from the template are added. - Only then does anything get written — atomically, with a backup of anything about to be overwritten, and a full rollback if any write in the batch fails.
This is why dotmaster sync is safe to run on every commit or as a
pre-commit hook, and why dotmaster check is meaningful in CI.
Preset profiles
dotmaster init --preset web_app # React/Next.js + ESLint + Prettier + Docker + CI
dotmaster init --preset backend_api # Python + FastAPI + Ruff + Docker + CI
dotmaster init --preset library # ESLint + Jest, no Docker
dotmaster init --preset monorepo # pnpm + ESLint + CI
A profile pre-fills the wizard (or, with --yes, applies directly) — nothing
is locked in, and dotmaster profile apply <name> merges a profile into an
existing config without overwriting anything you've already set explicitly.
dotmaster.yaml
version: "2"
project:
name: my-app
author: Jane Doe
stack:
languages: [javascript, typescript]
framework: nextjs
package_manager: pnpm
quality:
linter: eslint
formatter: prettier
testing: jest
infrastructure:
docker: true
docker_multistage: true
ci: github_actions
options:
offline: true # no network calls unless you opt out
plugins:
allow: [] # third-party plugins, opt-in by name (or ["*"])
Hand-editing is a first-class workflow: the file carries a
# yaml-language-server: $schema=... hint for editor autocomplete, and every
field is validated with a specific error (and a "did you mean" suggestion)
rather than a stack trace.
Plugin system
Every generator — .gitignore, Dockerfile, ruff.toml, CI workflows — is a
plugin: matches(config) decides if it's active, plan(config, ctx) returns
the files it wants. Built-ins are always available; third-party plugins
register via a dotmaster.plugins entry point and only load if named in
plugins.allow.
See docs/plugin-authoring.md for the full guide — most plugins are 30–80 lines, and it's the easiest way to contribute.
Development
git clone https://github.com/ahron-maslin/dotmaster
cd dotmaster
pip install -e ".[dev]"
pytest
ruff check . && ruff format --check . && mypy dotmaster
See CONTRIBUTING.md.
Security
options.offline defaults to true — no network call happens unless a
project explicitly opts out. All file writes are checked to stay inside the
project root. See SECURITY.md for the full policy and how to
report a vulnerability.
License
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file dotmaster-0.3.0.tar.gz.
File metadata
- Download URL: dotmaster-0.3.0.tar.gz
- Upload date:
- Size: 121.3 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/6.1.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
27014626b7ff77c0e699184d88d886efaf92c041f923cbc134c1f9a222230df8
|
|
| MD5 |
0834bbb1495e57292c767686cd7eb021
|
|
| BLAKE2b-256 |
80cc77f8dc65988e29ccf8f849bde03737ea35460f2c3cfbae06365199362efe
|
Provenance
The following attestation bundles were made for dotmaster-0.3.0.tar.gz:
Publisher:
release.yml on ahron-maslin/dotmaster
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
dotmaster-0.3.0.tar.gz -
Subject digest:
27014626b7ff77c0e699184d88d886efaf92c041f923cbc134c1f9a222230df8 - Sigstore transparency entry: 2259829028
- Sigstore integration time:
-
Permalink:
ahron-maslin/dotmaster@35c53271aa744e5fcdae4b54dc739a633caade8a -
Branch / Tag:
refs/tags/v0.3.0 - Owner: https://github.com/ahron-maslin
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@35c53271aa744e5fcdae4b54dc739a633caade8a -
Trigger Event:
push
-
Statement type:
File details
Details for the file dotmaster-0.3.0-py3-none-any.whl.
File metadata
- Download URL: dotmaster-0.3.0-py3-none-any.whl
- Upload date:
- Size: 82.2 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/6.1.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
b1396fa82f85feaad10c5c91000a1117353b2d3bfcc3f644031fb93f929d5785
|
|
| MD5 |
d857aee47ef7356440c2f25e4e6c61d5
|
|
| BLAKE2b-256 |
e56d4e1a62a40e9215339e0982bfa2a99e118e06380156213535a22feb711175
|
Provenance
The following attestation bundles were made for dotmaster-0.3.0-py3-none-any.whl:
Publisher:
release.yml on ahron-maslin/dotmaster
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
dotmaster-0.3.0-py3-none-any.whl -
Subject digest:
b1396fa82f85feaad10c5c91000a1117353b2d3bfcc3f644031fb93f929d5785 - Sigstore transparency entry: 2259829206
- Sigstore integration time:
-
Permalink:
ahron-maslin/dotmaster@35c53271aa744e5fcdae4b54dc739a633caade8a -
Branch / Tag:
refs/tags/v0.3.0 - Owner: https://github.com/ahron-maslin
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@35c53271aa744e5fcdae4b54dc739a633caade8a -
Trigger Event:
push
-
Statement type: