Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 40 additions & 0 deletions .claude/settings.json
Original file line number Diff line number Diff line change
@@ -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..."
}
]
}
]
}
}
38 changes: 38 additions & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
@@ -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 (`<summary>`, `<param>`, `<returns>`) on every public and internal member, `<inheritdoc/>` 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 <noreply@anthropic.com>
```

- **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.
9 changes: 9 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
16 changes: 15 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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 <noreply@anthropic.com>` 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

Expand Down
1 change: 1 addition & 0 deletions tests/linters/.cspell.json
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@
"Takumi",
"unreviewed",
"vsicons",
"vsocde",
"wayou",
"wordmark",
"wordmarks",
Expand Down