Global CLI tools for exporting a project-aware context without copying additional_tools
into every repository.
dev-tools is installed once as a global/private Python package.
Each project keeps only local context in .dev_tools/:
.dev_tools/context.toml.dev_tools/include.toml.dev_tools/exclude.toml.dev_tools/policy_manifest.toml.dev_tools/about_current_project.md.dev_tools/output/
dev-tools init automatically adds .dev_tools/ to .git/info/exclude.
It also applies high-level project bootstrap defaults for editor settings,
Python/TypeScript tooling, and local ignore policy.
dev-tools init records the concrete policies that were applied in the local
project policy manifest and registers the project path in a machine-local global
index. The index is intentionally local-only and exists so policy updates can be
planned or applied centrally without guessing which projects were initialized.
Use the generated CLI help as the source of truth for commands and arguments:
dev-tools --help
dev-tools init --help
dev-tools tree --help
dev-tools update-include-files --help
dev-tools run --help
dev-tools export-context --help
dev-tools projects --help
dev-tools policies --help
dev-tools global-cli --help
dev-tools global-cli setup --helpUse the interactive menu to see the workflow-oriented actions contributed by each domain:
dev-tools menuThe root CLI owns only global wiring and the menu command. Every project
operation is contributed by a domain through a CliContribution.
| Domain | Contribution class | Commands | Menu items |
|---|---|---|---|
project_init |
ProjectInitCliContribution |
init |
Initialize project context |
project_policy |
ProjectPolicyCliContribution |
projects, policies |
|
tree_generation |
TreeGenerationCliContribution |
tree |
Show project tree |
include_generation |
IncludeGenerationCliContribution |
update-include-files |
Update include files catalog |
export_context |
ExportContextCliContribution |
run, export-context |
Run export with about + tree; Run export without about/tree; Run export with tree only; Run export with about only |
global_cli |
GlobalCliCliContribution |
global-cli |
dev-tools init
dev-tools init --dry-run
dev-tools init --skip-pyproject --skip-package-json
dev-tools init --application-type python --toolset ruff,pyright --strictness high
dev-tools init --application-type ts --toolset prettier --strictness medium
dev-tools init .dev_tools/about_current_project.md
dev-tools menu
dev-tools run y y
dev-tools run n n
dev-tools run --include-tree --include-about
dev-tools update-include-files
dev-tools tree --print
dev-tools projects list
dev-tools projects doctor
dev-tools policies status
dev-tools policies plan --all
dev-tools policies apply --project-root /absolute/project/path
dev-tools policies plan --project-root /absolute/project/path --force
dev-tools policies apply --project-root /absolute/project/path --force
dev-tools global-cli status
dev-tools global-cli setup --dry-run
dev-tools global-cli setupdev-tools owns one machine-local standard for globally installed CLI tools:
C:\Users\User\repositories\global_cli\
bin\
uv_tools\
README.md
bin is the only directory from this layout that should be in PATH.
uv_tools stores uv-managed tool environments. dev-tools does not move
existing virtual environments or executable files into this layout; uv tool
remains the canonical installation mechanism.
Prepare or inspect the layout explicitly:
dev-tools global-cli status
dev-tools global-cli setup --dry-run
dev-tools global-cli setupThe setup command:
- creates
global_cli\,global_cli\bin\,global_cli\uv_tools\, andglobal_cli\README.mdwhen missing; - writes user-level
UV_TOOL_BIN_DIRtoglobal_cli\bin; - writes user-level
UV_TOOL_DIRtoglobal_cli\uv_tools; - ensures the user-level
Pathcontainsglobal_cli\binand does not containglobal_cli\,global_cli\uv_tools, or the default non-canonical uv tool binC:\Users\User\.local\bin; - updates global VS Code user
files.excludeso common Python cache folders such as__pycache__,.pytest_cache,.mypy_cache, and.ruff_cachestay hidden in the Explorer; - preserves unrelated
Pathentries and existingglobal_cli\README.mdcontent; - does not move existing executable shims or uv tool environments.
When bootstrapping this project before dev-tools is already installed
globally, run the command from the repository and then install with uv:
uv run dev-tools global-cli setup
uv tool install --reinstall .Open a new terminal after setup so Windows loads the updated user environment.
The root CLI does not know domain commands or menu items. It only collects domain contributions and asks each contribution to register its own surface.
The shared contract is dev_tools.cli.contracts.CliContribution:
register_commands(subparsers)adds argparse subcommands.get_menu_items()returns menu actions fordev-tools menu.- command and menu handlers call the domain application service.
The composition root is dev_tools.cli.containers.cli_container.CliContainer.
That container builds the ordered cli_contributions list consumed by:
CliArgumentParserFactory, for command registration;InteractiveMenuRunner, for menu item collection.
To add a new domain:
- Create the domain package, for example
src/dev_tools/new_domain/. - Put domain behavior in an application service, for example
new_domain/application_service.py. - Add
new_domain/cli.pywith aNewDomainCliContributionclass. - Implement
register_commands()and set each parser default to a command handler withparser.set_defaults(command_handler=...). - Implement
get_menu_items()and returnCliMenuItemvalues if the domain should appear indev-tools menu; return an empty tuple otherwise. - Add a dependency-injector container for the domain under
src/dev_tools/cli/containers/. - Wire the domain container in
AppContainer. - Wire the CLI contribution in
CliContainer.cli_contributions. - Add or update tests for the command parser and domain service.
- Update the "Current domain contributions" table above.
A contribution should stay thin: parse CLI arguments, call its own application service, print user-facing results, and avoid reaching into another domain's service directly.
By default, dev-tools init is equivalent to:
dev-tools init \
--application-type full \
--toolset all \
--strictness highSupported application types are python, ts, and full. The --toolset
argument accepts mypy, ruff, pyright, prettier, and all; it can be
repeated or passed as a comma-separated list:
dev-tools init --toolset ruff,pyright
dev-tools init --toolset ruff --toolset pyrightStrictness can be low, medium, or high. For Python, strictness maps to
Pyright's [tool.pyright] typeCheckingMode in pyproject.toml. For
TypeScript, high enables stricter tsconfig.json options.
The bootstrap writes policy, not environments. It never creates or stores a
.venv; it adds .venv/ and common cache/build folders to .gitignore, sets
the workspace VS Code interpreter path, and creates uv-oriented Python project
defaults when pyproject.toml is missing or can receive missing generated
sections safely. Machine-level user settings are configured by
dev-tools global-cli setup, not by per-project initialization.
Merge policy is intentionally conservative:
- missing files are created;
.gitignoreuses a replaceabledev-toolsmanaged block;.vscode/settings.jsonand.vscode/extensions.jsonare JSON-merged while preserving unknown user keys;pyproject.tomlgets missing generated TOML sections and missing generated keys inside existing sections, including Pyright's[tool.pyright]section when Pyright is enabled; existing values are preserved;package.jsonandtsconfig.jsonare JSON-merged while preserving unknown user keys;prettier.config.mjsis created only when missing, unless--forceis used.
Use --dry-run to print the plan without writing files:
dev-tools init --dry-runFor mature projects where package metadata is already intentionally managed, skip the generated project-file policies:
dev-tools init --skip-pyproject --skip-package-json
dev-tools init --application-type python --toolset ruff --skip-pyprojectThese flags are recorded in .dev_tools/policy_manifest.toml, so later
dev-tools policies plan and dev-tools policies apply continue to skip those
files.
Use --force when you intentionally want generated target files such as
pyproject.toml or package.json to be overwritten.
Initialization writes a local machine-only policy manifest:
.dev_tools/policy_manifest.tomlThe manifest records the init settings, the dev-tools version at first init,
and each concrete policy id/revision with its latest status. This is the source
of truth for what was applied to the project.
The global project index lives under the user-local dev-tools state directory and stores only project paths plus manifest locations. Use:
dev-tools projects list
dev-tools projects doctorPolicy updates are explicit. plan is read-only; apply mutates files and then
updates the manifest:
dev-tools policies status
dev-tools policies plan --all
dev-tools policies apply --allWhen a managed JSON/TOML shape conflicts with an existing project value, the
default plan reports the conflict and skips that target file. Use --force on
policies plan to preview overwrite behavior, and --force on policies apply
only when overwriting conflicting managed values is intentional.
- Run
dev-tools initinside a git project. - Edit
.dev_tools/about_current_project.md. - Run
dev-tools update-include-files. - Open
.dev_tools/include.toml. - Uncomment the file paths that should be exported.
- Run
dev-tools run y y.
Output order:
- about current project
- generated tree
- content of selected files
Generated files are written to .dev_tools/output/.