diff --git a/.claude/settings.json b/.claude/settings.json new file mode 100644 index 0000000..ef9b267 --- /dev/null +++ b/.claude/settings.json @@ -0,0 +1,40 @@ +{ + "permissions": { + "allow": ["Agent"] + }, + "hooks": { + "PostToolUse": [ + { + "matcher": "Edit|Write|NotebookEdit", + "hooks": [ + { + "type": "command", + "command": "f=$(jq -r '.tool_input.file_path // .tool_input.notebook_path // empty'); case \"$f\" in \"\"|*/bin/*|*/obj/*) exit 0;; esac; case \"$f\" in *.md|*.json|*.jsonc|*.yml|*.yaml|*.toml|*.xml|*.csproj|*.slnx) ;; *) exit 0;; esac; command -v dprint >/dev/null 2>&1 && [ -f \"$f\" ] && dprint fmt \"$f\" 2>&1; true", + "statusMessage": "Formatting (dprint)..." + }, + { + "type": "command", + "command": "f=$(jq -r '.tool_input.file_path // empty'); case \"$f\" in *.md) ;; *) exit 0;; esac; command -v npx >/dev/null 2>&1 || exit 0; if [ -f \"$f\" ]; then out=$(npx --yes markdownlint-cli2@0.23.0 --config tests/linters/.markdownlint.yml --fix \"$f\" 2>&1); [ $? -ne 0 ] && { echo \"$out\" >&2; exit 2; }; fi; true", + "statusMessage": "Linting Markdown..." + }, + { + "type": "command", + "command": "f=$(jq -r '.tool_input.file_path // .tool_input.notebook_path // empty'); case \"$f\" in \"\"|*/bin/*|*/obj/*|*.svg) exit 0;; esac; command -v npx >/dev/null 2>&1 || exit 0; if [ -f \"$f\" ]; then out=$(npx --yes cspell@10.0.1 lint --config tests/linters/.cspell.json --no-progress \"$f\" 2>&1); [ $? -ne 0 ] && { echo \"$out\" >&2; exit 2; }; fi; true", + "statusMessage": "Spell checking (CSpell)..." + } + ] + } + ], + "Stop": [ + { + "hooks": [ + { + "type": "command", + "command": "out=$(dotnet build \"source/CLI.NET Core.slnx\" 2>&1); if [ $? -ne 0 ]; then echo \"$out\" >&2; exit 2; fi", + "statusMessage": "Building the solution..." + } + ] + } + ] + } +} diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000..04e30a3 --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,38 @@ +# CLAUDE.md + +Guidance for AI assistants working on CLI.NET Core. + +## What This Project Is + +CLI.NET Core is a .NET command line application framework, built in the style of ASP.NET Core: it lets consumers define commands and command-line arguments much the same way they would define actions and parameters for a Web API. The repository holds one solution, [`source/CLI.NET Core.slnx`](source/CLI.NET%20Core.slnx), with two projects — the framework itself (`clinet-core`) and a sample app that references it (`sample-app`). Both target `net10.0` with nullable reference types and implicit usings enabled. + +## Golden Rules + +- **Match the surrounding code** This code is heavily and consistently documented — follow it. +- **Formatting is owned by dprint** Markdown, JSON, XML (including `.csproj`/`.slnx`), YAML, and TOML — never add a lint rule that reformats one of these. Run `dprint fmt` before finishing. **C# is not covered by dprint** (there is no C# plugin configured); its whitespace comes from [`.editorconfig`](.editorconfig), so review it by eye. +- **Run the linters before finishing** — there is no npm-script wrapper, so invoke them directly: + + ```shell + dprint check "**/*" + npx --yes cspell@10.0.1 lint --config tests/linters/.cspell.json --no-progress "**/*" + npx --yes markdownlint-cli2@0.23.0 --config tests/linters/.markdownlint.yml "**/*.md" "#**/bin/**" "#**/obj/**" + ``` + + This file is Markdown and is linted too. +- **Markdown headings are title case** at every level, in every file. Preserve the real casing of code spans, brand names (`dprint`), and acronyms. +- **Prose uses periods, not semicolons.** In prose (docs, XML documentation comments, commit messages, this file) end each sentence with a period rather than joining two with a semicolon. Plain in-code comments (`//`) do the reverse: sentences are separated by semicolons and the last one takes no terminal punctuation. +- **C# structure**: file-scoped namespaces, an XML documentation comment (``, ``, ``) on every public and internal member, `` for members that implement an interface or override a base member, `sealed` classes by default (composition over inheritance for anything that would otherwise need to extend a sealed framework type), explicit `this.` on member access, expression-bodied members where the implementation is a single expression, and `camelCase` private fields with no underscore. +- **Nullable reference types and implicit usings are enabled everywhere.** Write genuinely null-safe code rather than silencing the analyzer. +- **Files and directories are kebab-case**, except well-known and tool-mandated names (`README.md`, `LICENSE`, `.editorconfig`, ...). Inside a C# project's own source tree, directories and files switch to PascalCase, one type per file. +- **Every dependency is pinned to an exact version — never a range.** NuGet packages, dprint plugins, and the linter versions CI installs are all pinned exactly. Every C# project sets `RestorePackagesWithLockFile`, so a `PackageReference` version bump must be followed by `dotnet restore` and the resulting `packages.lock.json` change committed alongside it. +- **Write commit messages by the rules** — the 50/72 rule, a title-cased, past-tense subject, and a prose body. State whether AI was involved and, if it was, what exactly the AI did — this project is developed openly with AI assistance and the commit history is where that is tracked (see the "Use of AI" section of the [root README](README.md)). When you did any of the work, add the trailer this project uses (not a model-specific one): + + ```text + Co-Authored-By: Claude + ``` + +- **Delegating to subagents is pre-approved.** `.claude/settings.json` allows the agent/subagent tool by default, so use one whenever a task genuinely benefits from parallel or isolated work, without asking first. + +## Conventions in Brief + +Files use file-scoped namespaces and, in larger files, `#region` blocks (`Constructors`, `Private Fields`, `Public Methods`, and so on) to group members — small files skip regions entirely. Every public and internal member is documented with XML comments that explain *why*, not just what. Sealed types compose the framework types they wrap instead of inheriting from them. Markdown headings are title case everywhere, and prose ends sentences with periods; plain code comments do the reverse. diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 60f9b0f..c711c76 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -17,6 +17,15 @@ Fork the repository and work on a feature branch. Pull requests are always welco - Run the linters and the code formatter before opening the pull request (see [Tooling](docs/developer-manual/tooling/README.md)). The same checks run in [Continuous Integration](docs/developer-manual/tooling/continuous-integration.md) on every push. - Write commit messages by [the project's rules](docs/developer-manual/conventions/commit-messages.md). +## Using AI to Contribute + +Using AI tools to help write a contribution is fine, but two rules apply, without exception: + +- **Disclose it.** Say in the pull request description, and in the commit messages themselves, whether AI was involved and what it did — the same rule that governs every commit to this repository (see [Commit Messages](docs/developer-manual/conventions/commit-messages.md)). An undisclosed AI contribution is treated as a violation of this policy, not as a neutral omission. +- **Review it yourself, fully, before submitting.** You are responsible for every line of a contribution as if you had written it by hand: you must understand it, be able to explain and defend it, and have actually run the relevant tests and linters against it. AI is a tool you use, not a substitute for that responsibility. + +A pull request that is raw, unreviewed AI output — one the contributor cannot explain or has not verified — **will be rejected**, disclosed or not. This is not about rejecting AI assistance, it is about rejecting contributions nobody has actually taken responsibility for. + ## Update the Project's Records A pull request that adds a contribution is expected to also update the records that track the project's history: diff --git a/README.md b/README.md index a51cb6e..08888dc 100644 --- a/README.md +++ b/README.md @@ -23,9 +23,23 @@ The project uses a set of linters and a code formatter to (1) find and correct p - **[MarkdownLint](tests/linters/.markdownlint.yml)**, a linter for Markdown files, which ensures that the Markdown files are consistently formatted and standards are enforced. - **[dprint](dprint.json)**, an unopinionated, configurable code formatter with plugins for many languages. This code formatter is used to format Markdown, JSON, XML, YAML, and TOML files in the project. +## Use of AI + +This project is developed with the help of AI and I want to be fully transparent about that. The heart of the project — its architecture, its public API, and the implementation of its core — was and will continue to be written by hand, by me. AI is a tool that I use for the work around that core, never a substitute for it, and everything an AI produces is reviewed and, where necessary, rewritten by me before it is committed. Concretely, I use AI for the following kinds of tasks: + +- **Documentation** — Writing and revising the documentation, the read me files, and code comments. +- **Design assets** — Generating logo designs and other visual assets. +- **Boilerplate** — Generating repetitive, mechanical code, project scaffolding, and configuration files. +- **Difficult bugs** — Tracking down bugs where a second pair of eyes helps. +- **Architecture** — Discussing design and architecture decisions as a sounding board. The decisions themselves are always mine. + +Every commit message states whether AI was involved and, if it was, what exactly the AI did. Such commits additionally carry a `Co-Authored-By: Claude ` trailer, so that the extent of AI involvement can be traced through the Git history at any point. Commits without such a note were written entirely by hand. + +This is my own policy for my own commits. If you are contributing to the project yourself, see [`CONTRIBUTING.md`](CONTRIBUTING.md) for the AI-assistance rules that apply to contributions. + ## Contributing -If you'd like to contribute, there are multiple ways you can help out — bug reports, feature requests, or code. See [`CONTRIBUTING.md`](CONTRIBUTING.md) for the full process. Participation is governed by the [Code of Conduct](CODE_OF_CONDUCT.md). +If you'd like to contribute, there are multiple ways you can help out — bug reports, feature requests, or code. See [`CONTRIBUTING.md`](CONTRIBUTING.md) for the full process, including how AI-assisted contributions are handled. Participation is governed by the [Code of Conduct](CODE_OF_CONDUCT.md). ## Security diff --git a/tests/linters/.cspell.json b/tests/linters/.cspell.json index b4d21ea..789b784 100644 --- a/tests/linters/.cspell.json +++ b/tests/linters/.cspell.json @@ -93,6 +93,7 @@ "Takumi", "unreviewed", "vsicons", + "vsocde", "wayou", "wordmark", "wordmarks",