Repository: kedro-org/kedro
Pull request: Rename addons to tools
> **NOTE:** Kedro datasets are moving from `kedro.extras.datasets` to a separate `kedro-datasets` package in
> [`kedro-plugins` repository](https://github.com/kedro-org/kedro-plugins). Any changes to the dataset implementations
> should be done by opening a pull request in that repository.
## Description
<!-- Why was this PR created? -->
Follow-on action from #3054 

## Development notes
<!-- What have you changed, and how has this been tested? -->
**Note: Ignore failing unit-tests.** Unit tests will fail until [changes go through on kedro-starters](https://github.com/kedro-org/kedro-starters/pull/189), it's a fun circular dependency 🔁 

~~Blocked by :~~
- [x] #3358  

## Developer Certificate of Origin
We need all contributions to comply with the [Developer Certificate of Origin (DCO)](https://developercertificate.org/). All commits must be signed off by including a `Signed-off-by` line in the commit message. [See our wiki for guidance](https://github.com/kedro-org/kedro/wiki/Guidelines-for-contributing-developers/).

If your PR is blocked due to unsigned commits, then you must follow the instructions under "Rebase the branch" on the GitHub Checks page for your PR. This will retroactively add the sign-off to all unsigned commits and allow the DCO check to pass.

## Checklist

- [ ] Read the [contributing](https://github.com/kedro-org/kedro/blob/main/CONTRIBUTING.md) guidelines
- [x] Signed off each commit with a [Developer Certificate of Origin (DCO)](https://docs.github.com/en/repositories/managing-your-repositorys-settings-and-features/managing-repository-settings/managing-the-commit-signoff-policy-for-your-repository)
- [x] Opened this PR as a 'Draft Pull Request' if it is work-in-progress
- [ ] Updated the documentation to reflect the code changes
- [x] Added a description of this change in the [`RELEASE.md`](https://github.com/kedro-org/kedro/blob/main/RELEASE.md) file
- [ ] Added tests to cover my changes
- [ ] Checked if this change will affect Kedro-Viz, and if so, communicated that with the Viz team


Problem statement:
Iterate on feedback on Project Creation Flow 
Following the **internal** user feedback session on 13/09/2023:

We presented the following prototype
```
(my-virtual-environment) ➜  kedro new 

Project Name
============
Please enter a human readable name for your new project.
Spaces, hyphens, and underscores are allowed. 
To skip this step in future use --name

[New Kedro Project]: My ML Pipeline 


Project Add-Ons 
================
Select which add-ons you'd like to include. 
To skip this step in future use --add-ons
To read more about these add-ons and what they do visit: kedro.org/

Add-Ons 
1) Lint:        Provides a basic linting set up with Black, Ruff 
2) Test:        Provides basic testing set up with pytest 
3) Log:         Provides more logging options, environment specific,  
4) Docs:        Provides basic documentations setup with Sphinx
5) Data :        Provides folder structure for data management  ???? What shall we call this 
6) PySpark:     Provides set up configuration for working with PySpark
7) Kedro-Viz:   Provides Kedro's native visualisation tool 

Which add-ons would you like to include in your project? [None/1-4/1,3/all]: 1,2

Example Pipeline 
================
Select whether you would like an example spaceflights pipeline included in your project.
To skip this step in the future use --example=y/n
To read more about how examples work visit: kedro.org/

Would you like to include an example pipeline? [Y\n]:Y

Congratulations! 
Your project My ML Pipeline has been created in directory /my_ml_pipeline 
You selected the following add-ons: Lint, Test 
It has been created with an example pipeline.
```

We received feedback on the following points: (❓flagged for further discussion)

- the name add-ons makes it sound more optional, which can be misleading (possible names: tools, options, utilities, plugins) ❓
should we allow users to define preset groups of add-ons?
- adjusting the copy of the CLI wizard to better highlight that we are recommending tools for certain functionality i.e. Black/Pytest instead of just Lint/Test ❓
- an interactive playground/sandbox UI for generating kedro new commands in the docs. Allow people to experiment with options and preview what the project would look like.
- users suggested that the default state should include examples, but no add-ons, as the most likely user type to use a basic new command is a new command. ❓
- if the user does not select the testing add-on the example project should not contain tests. (especially because we wouldn't have installed the testing dependencies)
- providing a custom flag to bypass the interactive flow and apply defaults to all flags that aren't provided. this will help for programmatic creation, and also expert users who want to skip the flow. ❓
- the --starter flow should stay independent of the addons flow to allow users to start a project with their own custom project.

Next Steps: 
- we have a **external** user feedback session where we aim to collect more feedback then have a discussion about which points we'd like to address.

Hints from issue discussion:
Following the **external** user feedback section on 4/10/2023: 

We received feedback on the following points 
- a flag to indicate that they wanted default values 
- users were happy to go through the interactive flow if no flags were used 
- users wanted to ability to create their own add-ons 
- users understood that a large list of add-ons might be intimidating but wanted 'advanced add-ons' perhaps accessible only via CLI 
- users were interested in add-ons for precommit, github actions, docker add-ons 
- users wanted to be able to access add-ons beyond the project creation flow (add them later) 
- users wanted an easier way to create a starter as a way to preset add-ons 
- users wanted to be make one line changes to a starter easily 
Following feedback review we have decided to action the following for our 19.0 release 

- add-ons wil be renamed to tools 
- copy at the selection step will be updated to mention the benefits of using "software engineering best practice" 
- when a flag isnt chosen, the user will go through those steps of the interactive flow 
- copy at the end of the interactive flow to further highlight the ability to use flags to bypass the interactive flow 

---

Features that we would like to discuss for post 19.0 will be tracked here #3135 
Thanks a lot for the summary @amandakys ! @merelcht if you want to open follow-up tickets and close this one go ahead, in any case the scope of the project creation flow for 0.19.0 is finalised and we'll continue improving it afterwards in @amandakys's https://github.com/kedro-org/kedro/issues/3135
@amandakys will catch up with @AhdraMeraliQB , @SajidAlamQB , @lrcouto to make sure there's time to make the adjustments listed in https://github.com/kedro-org/kedro/issues/3054#issuecomment-1750416068 , possibly add follow-up tickets if needed, and then we can close this one.
Updated copy for the prototype: 

```
(my-virtual-environment) ➜  kedro new 

Project Name
============
Please enter a human readable name for your new project.
Spaces, hyphens, and underscores are allowed. 
To skip this step in future use --name

[New Kedro Project]: My ML Pipeline 


Project Tools
================
These optional tools are here to help you apply software engineering best practices to your project quickly and easily. 
To skip this step in future use --add-ons
To read more about these add-ons and what they do visit: kedro.org/

Tools:
1) Lint:           Provides a basic linting set up with Black, Ruff 
2) Test:           Provides basic testing set up with pytest 
3) Log:            Provides more logging options, environment specific,  
4) Docs:           Provides basic documentations setup with Sphinx
5) Data Folder:    Provides folder structure for data management  
6) PySpark:        Provides set up configuration for working with PySpark
7) Kedro-Viz:      Provides Kedro's native visualisation tool 

Which tools would you like to include in your project? [None/1-4/1,3/all]: 1,2

Example Pipeline 
================
Select whether you would like an example spaceflights pipeline included in your project.
To skip this step in the future use --example=y/n
To read more about how examples work visit: kedro.org/

Would you like to include an example pipeline? [y\N]:N

Congratulations! 
Your project My ML Pipeline has been created in directory /my_ml_pipeline 
You selected the following tools: Lint, Test 
It has been created with an example pipeline.

To skip the interactive flow you can run `kedro new` with
kedro new --addons=<your-addons> --example=<yes/no>
```
2023-11-14
-  Aiming to get #3076 finished this week

Follow up for next week:
- Review the whole kedro new flow to see if there is any more changes needed.
- Create remaining engineering ticket base on the feedback.

Commit message: Replace add-ons with tools

Signed-off-by: Ahdra Merali <ahdra.merali@quantumblack.com>

Patch to review:
diff --git a/features/steps/cli_steps.py b/features/steps/cli_steps.py
index 355a745702..4494aade8a 100644
--- a/features/steps/cli_steps.py
+++ b/features/steps/cli_steps.py
@@ -151,7 +151,7 @@ def create_config_file(context):
     context.root_project_dir = context.temp_dir / context.project_name
     context.package_name = context.project_name.replace("-", "_")
     config = {
-        "add_ons": "1-5",
+        "tools": "1-5",
         "project_name": context.project_name,
         "example_pipeline": "no",
         "repo_name": context.project_name,
diff --git a/features/steps/test_starter/cookiecutter.json b/features/steps/test_starter/cookiecutter.json
index 70472b8afc..f95cb7ede5 100644
--- a/features/steps/test_starter/cookiecutter.json
+++ b/features/steps/test_starter/cookiecutter.json
@@ -3,5 +3,5 @@
     "repo_name": "{{ cookiecutter.project_name.replace(' ', '-').lower().strip('-') }}",
     "python_package": "{{ cookiecutter.project_name.replace(' ', '_').replace('-', '_').lower() }}",
     "kedro_version": "{{ cookiecutter.kedro_version }}",
-    "add_ons": "none"
+    "tools": "none"
 }
diff --git a/features/steps/test_starter/{{ cookiecutter.repo_name }}/pyproject.toml b/features/steps/test_starter/{{ cookiecutter.repo_name }}/pyproject.toml
index 785b1f5584..ea5b0d3ef5 100644
--- a/features/steps/test_starter/{{ cookiecutter.repo_name }}/pyproject.toml	
+++ b/features/steps/test_starter/{{ cookiecutter.repo_name }}/pyproject.toml	
@@ -35,7 +35,7 @@ namespaces = false
 package_name = "{{ cookiecutter.python_package }}"
 project_name = "{{ cookiecutter.project_name }}"
 kedro_init_version = "{{ cookiecutter.kedro_version }}"
-add_ons = "{{ cookiecutter.add_ons | default('') | string | replace('\"', '\\\"') }}"
+tools = "{{ cookiecutter.tools | default('') | string | replace('\"', '\\\"') }}"
 
 [tool.pytest.ini_options]
 addopts = """
diff --git a/kedro/framework/cli/starters.py b/kedro/framework/cli/starters.py
index 5d7b223c86..4209643ec3 100644
--- a/kedro/framework/cli/starters.py
+++ b/kedro/framework/cli/starters.py
@@ -31,11 +31,11 @@
     command_with_verbosity,
 )
 
-# TODO(lrcouto): Insert actual link to the documentation (Visit: kedro.org/{insert-documentation} to find out more about these add-ons.).
-ADDON_ARG_HELP = """
-Select which add-ons you'd like to include. By default, none are included.\n
+# TODO(lrcouto): Insert actual link to the documentation (Visit: kedro.org/{insert-documentation} to find out more about these tools.).
+TOOLS_ARG_HELP = """
+Select which tools you'd like to include. By default, none are included.\n
 
-Add-Ons\n
+Tools\n
 1) Linting: Provides a basic linting setup with Black and Ruff\n
 2) Testing: Provides basic testing setup with pytest\n
 3) Custom Logging: Provides more logging options\n
@@ -45,9 +45,9 @@
 7) Kedro Viz: Provides Kedro's native visualisation tool \n
 
 Example usage:\n
-kedro new --addons=lint,test,log,docs,data,pyspark,viz (or any subset of these options)\n
-kedro new --addons=all\n
-kedro new --addons=none
+kedro new --tools=lint,test,log,docs,data,pyspark,viz (or any subset of these options)\n
+kedro new --tools=all\n
+kedro new --tools=none
 """
 CONFIG_ARG_HELP = """Non-interactive mode, using a configuration yaml file. This file
 must supply  the keys required by the template's prompts.yml. When not using a starter,
@@ -107,7 +107,7 @@ class KedroStarterSpec:  # noqa: too-few-public-methods
 
 _OFFICIAL_STARTER_SPECS = {spec.alias: spec for spec in _OFFICIAL_STARTER_SPECS}
 
-ADD_ONS_SHORTNAME_TO_NUMBER = {
+TOOLS_SHORTNAME_TO_NUMBER = {
     "lint": "1",
     "test": "2",
     "log": "3",
@@ -116,7 +116,7 @@ class KedroStarterSpec:  # noqa: too-few-public-methods
     "pyspark": "6",
     "viz": "7",
 }
-NUMBER_TO_ADD_ONS_NAME = {
+NUMBER_TO_TOOLS_NAME = {
     "1": "Linting",
     "2": "Testing",
     "3": "Custom Logging",
@@ -170,13 +170,13 @@ def starter():
 @click.option("--starter", "-s", "starter_alias", help=STARTER_ARG_HELP)
 @click.option("--checkout", help=CHECKOUT_ARG_HELP)
 @click.option("--directory", help=DIRECTORY_ARG_HELP)
-@click.option("--addons", "-a", "selected_add_ons_flag", help=ADDON_ARG_HELP)
+@click.option("--tools", "-a", "selected_tools", help=TOOLS_ARG_HELP)
 @click.option("--name", "-n", "project_name", help=NAME_ARG_HELP)
 @click.option("--example", "-e", "example_pipeline", help=EXAMPLE_ARG_HELP)
 def new(  # noqa: PLR0913
     config_path,
     starter_alias,
-    selected_add_ons_flag,
+    selected_tools,
     project_name,
     checkout,
     directory,
@@ -217,12 +217,12 @@ def new(  # noqa: PLR0913
     prompts_required = _get_prompts_required(cookiecutter_dir)
 
     # Format user input where necessary
-    if selected_add_ons_flag is not None:
-        selected_add_ons_flag = selected_add_ons_flag.lower()
+    if selected_tools is not None:
+        selected_tools = selected_tools.lower()
 
     # Select which prompts will be displayed to the user based on which flags were selected.
     prompts_required = _select_prompts_to_display(
-        prompts_required, selected_add_ons_flag, project_name, example_pipeline
+        prompts_required, selected_tools, project_name, example_pipeline
     )
 
     # We only need to make cookiecutter_context if interactive prompts are needed.
@@ -243,7 +243,7 @@ def new(  # noqa: PLR0913
         prompts_required=prompts_required,
         config_path=config_path,
         cookiecutter_context=cookiecutter_context,
-        selected_add_ons_flag=selected_add_ons_flag,
+        selected_tools=selected_tools,
         project_name=project_name,
         example_pipeline=example_pipeline,
     )
@@ -254,7 +254,7 @@ def new(  # noqa: PLR0913
         directory=directory,
     )
 
-    project_template = fetch_template_based_on_add_ons(template_path, cookiecutter_args)
+    project_template = fetch_template_based_on_tools(template_path, cookiecutter_args)
 
     _create_project(project_template, cookiecutter_args)
 
@@ -399,7 +399,7 @@ def _get_extra_context(  # noqa: PLR0913
     prompts_required: dict,
     config_path: str,
     cookiecutter_context: OrderedDict,
-    selected_add_ons_flag: str | None,
+    selected_tools: str | None,
     project_name: str | None,
     example_pipeline: str | None,
 ) -> dict[str, str]:
@@ -412,7 +412,7 @@ def _get_extra_context(  # noqa: PLR0913
         config_path: a string containing the value for the --config flag, or
             None in case the flag wasn't used.
         cookiecutter_context: the context for Cookiecutter templates.
-        selected_add_ons_flag: a string containing the value for the --addons flag,
+        selected_tools: a string containing the value for the --tools flag,
             or None in case the flag wasn't used.
         project_name: a string containing the value for the --name flag, or
             None in case the flag wasn't used.
@@ -438,22 +438,22 @@ def _get_extra_context(  # noqa: PLR0913
     # Format
     extra_context.setdefault("kedro_version", version)
 
-    add_ons = _convert_addon_names_to_numbers(selected_add_ons_flag)
+    tools = _convert_tools_names_to_numbers(selected_tools)
 
-    if add_ons is not None:
-        extra_context["add_ons"] = add_ons
+    if tools is not None:
+        extra_context["tools"] = tools
 
     if project_name is not None:
         extra_context["project_name"] = project_name
 
-    # Map the selected add on lists to readable name
-    add_ons = extra_context.get("add_ons")
-    if add_ons:
-        extra_context["add_ons"] = [
-            NUMBER_TO_ADD_ONS_NAME[add_on]
-            for add_on in _parse_add_ons_input(add_ons)  # type: ignore
+    # Map the selected tools lists to readable name
+    tools = extra_context.get("tools")
+    if tools:
+        extra_context["tools"] = [
+            NUMBER_TO_TOOLS_NAME[tool]
+            for tool in _parse_tools_input(tools)  # type: ignore
         ]
-        extra_context["add_ons"] = str(extra_context["add_ons"])
+        extra_context["tools"] = str(extra_context["tools"])
 
     extra_context["example_pipeline"] = (
         _parse_yes_no_to_bool(
@@ -466,33 +466,33 @@ def _get_extra_context(  # noqa: PLR0913
     return extra_context
 
 
-def _convert_addon_names_to_numbers(selected_add_ons_flag: str | None) -> str | None:
-    """Prepares add-on selection from the CLI input to the correct format
+def _convert_tools_names_to_numbers(selected_tools: str | None) -> str | None:
+    """Prepares tools selection from the CLI input to the correct format
     to be put in the project configuration, if it exists.
-    Replaces add-on strings with the corresponding prompt number.
+    Replaces tool strings with the corresponding prompt number.
 
     Args:
-        selected_add_ons_flag: a string containing the value for the --addons flag,
+        selected_tools: a string containing the value for the --tools flag,
             or None in case the flag wasn't used, i.e. lint,docs.
 
     Returns:
-        String with the numbers corresponding to the desired add_ons, or
-        None in case the --addons flag was not used.
+        String with the numbers corresponding to the desired tools, or
+        None in case the --tools flag was not used.
     """
-    if selected_add_ons_flag is None:
+    if selected_tools is None:
         return None
 
-    addons = []
-    for addon in selected_add_ons_flag.lower().split(","):
-        addon_short_name = addon.strip()
-        if addon_short_name in ADD_ONS_SHORTNAME_TO_NUMBER:
-            addons.append(ADD_ONS_SHORTNAME_TO_NUMBER[addon_short_name])
-    return ",".join(addons)
+    tools = []
+    for tool in selected_tools.lower().split(","):
+        tool_short_name = tool.strip()
+        if tool_short_name in TOOLS_SHORTNAME_TO_NUMBER:
+            tools.append(TOOLS_SHORTNAME_TO_NUMBER[tool_short_name])
+    return ",".join(tools)
 
 
 def _select_prompts_to_display(
     prompts_required: dict,
-    selected_add_ons_flag: str,
+    selected_tools: str,
     project_name: str,
     example_pipeline: str,
 ) -> dict:
@@ -503,7 +503,7 @@ def _select_prompts_to_display(
     Args:
         prompts_required: a dictionary of all the prompts that will be shown to
             the user on project creation.
-        selected_add_ons_flag: a string containing the value for the --addons flag,
+        selected_tools: a string containing the value for the --tools flag,
             or None in case the flag wasn't used.
         project_name: a string containing the value for the --name flag, or
             None in case the flag wasn't used.
@@ -513,26 +513,26 @@ def _select_prompts_to_display(
     Returns:
         the prompts_required dictionary, with all the redundant information removed.
     """
-    valid_addons = list(ADD_ONS_SHORTNAME_TO_NUMBER) + ["all", "none"]
+    valid_tools = list(TOOLS_SHORTNAME_TO_NUMBER) + ["all", "none"]
 
-    if selected_add_ons_flag is not None:
-        addons = re.sub(r"\s", "", selected_add_ons_flag).split(",")
-        for addon in addons:
-            if addon not in valid_addons:
+    if selected_tools is not None:
+        tools = re.sub(r"\s", "", selected_tools).split(",")
+        for tool in tools:
+            if tool not in valid_tools:
                 click.secho(
-                    "Please select from the available add-ons: lint, test, log, docs, data, pyspark, viz, all, none",
+                    "Please select from the available tools: lint, test, log, docs, data, pyspark, viz, all, none",
                     fg="red",
                     err=True,
                 )
                 sys.exit(1)
-        if ("none" in addons or "all" in addons) and len(addons) > 1:
+        if ("none" in tools or "all" in tools) and len(tools) > 1:
             click.secho(
-                "Add-on options 'all' and 'none' cannot be used with other options",
+                "Tools options 'all' and 'none' cannot be used with other options",
                 fg="red",
                 err=True,
             )
             sys.exit(1)
-        del prompts_required["add_ons"]
+        del prompts_required["tools"]
 
     if project_name is not None:
         if not re.match(r"^[\w -]{2,}$", project_name):
@@ -618,20 +618,20 @@ def _fetch_config_from_user_prompts(
     return config
 
 
-def fetch_template_based_on_add_ons(template_path, cookiecutter_args: dict[str, Any]):
+def fetch_template_based_on_tools(template_path, cookiecutter_args: dict[str, Any]):
     extra_context = cookiecutter_args["extra_context"]
-    # If 'add_ons' or 'example_pipeline' are not specified in prompts.yml and not prompted in 'kedro new' options,
+    # If 'tools' or 'example_pipeline' are not specified in prompts.yml and not prompted in 'kedro new' options,
     # default options will be used instead
-    add_ons = extra_context.get("add_ons", [])
+    tools = extra_context.get("tools", [])
     example_pipeline = extra_context.get("example_pipeline", False)
     starter_path = "git+https://github.com/kedro-org/kedro-starters.git"
-    if "Pyspark" in add_ons and "Kedro Viz" in add_ons:
+    if "Pyspark" in tools and "Kedro Viz" in tools:
         # Use the spaceflights-pyspark-viz starter if both Pyspark and Kedro Viz are chosen.
         cookiecutter_args["directory"] = "spaceflights-pyspark-viz"
-    elif "Pyspark" in add_ons:
+    elif "Pyspark" in tools:
         # Use the spaceflights-pyspark starter if only Pyspark is chosen.
         cookiecutter_args["directory"] = "spaceflights-pyspark"
-    elif "Kedro Viz" in add_ons:
+    elif "Kedro Viz" in tools:
         # Use the spaceflights-pandas-viz starter if only Kedro Viz is chosen.
         cookiecutter_args["directory"] = "spaceflights-pandas-viz"
     elif example_pipeline:
@@ -738,62 +738,62 @@ def _validate_config_file_inputs(config: dict[str, str]):
         click.secho(project_name_validation_config["error_message"], fg="red", err=True)
         sys.exit(1)
 
-    input_add_ons = config.get("add_ons", "none")
-    add_on_validation_config = {
+    input_tools = config.get("tools", "none")
+    tools_validation_config = {
         "regex_validator": r"^(all|none|(( )*\d*(,\d*)*(,( )*\d*)*( )*|( )*((\d+-\d+)|(\d+ - \d+))( )*))$",
-        "error_message": f"'{input_add_ons}' is an invalid value for project add-ons. Please select valid options for add-ons using comma-separated values, ranges, or 'all/none'.",
+        "error_message": f"'{input_tools}' is an invalid value for project tools. Please select valid options for tools using comma-separated values, ranges, or 'all/none'.",
     }
 
-    if not re.match(add_on_validation_config["regex_validator"], input_add_ons.lower()):
-        message = add_on_validation_config["error_message"]
+    if not re.match(tools_validation_config["regex_validator"], input_tools.lower()):
+        message = tools_validation_config["error_message"]
         click.secho(message, fg="red", err=True)
         sys.exit(1)
 
-    selected_add_ons = _parse_add_ons_input(input_add_ons)
-    _validate_selection(selected_add_ons)
+    selected_tools = _parse_tools_input(input_tools)
+    _validate_selection(selected_tools)
     _validate_regex("yes_no", config.get("example_pipeline", "no"))
 
 
-def _validate_selection(add_ons: list[str]):
+def _validate_selection(tools: list[str]):
     # start validating from the end, when user select 1-20, it will generate a message
     # '20' is not a valid selection instead of '8'
-    for add_on in add_ons[::-1]:
-        if add_on not in NUMBER_TO_ADD_ONS_NAME:
-            message = f"'{add_on}' is not a valid selection.\nPlease select from the available add-ons: 1, 2, 3, 4, 5, 6, 7."  # nosec
+    for tool in tools[::-1]:
+        if tool not in NUMBER_TO_TOOLS_NAME:
+            message = f"'{tool}' is not a valid selection.\nPlease select from the available tools: 1, 2, 3, 4, 5, 6, 7."  # nosec
             click.secho(message, fg="red", err=True)
             sys.exit(1)
 
 
-def _parse_add_ons_input(add_ons_str: str):
-    """Parse the add-ons input string.
+def _parse_tools_input(tools_str: str):
+    """Parse the tools input string.
 
     Args:
-        add_ons_str: Input string from prompts.yml.
+        tools_str: Input string from prompts.yml.
 
     Returns:
-        list: List of selected add-ons as strings.
+        list: List of selected tools as strings.
     """
 
     def _validate_range(start, end):
         if int(start) > int(end):
-            message = f"'{start}-{end}' is an invalid range for project add-ons.\nPlease ensure range values go from smaller to larger."
+            message = f"'{start}-{end}' is an invalid range for project tools.\nPlease ensure range values go from smaller to larger."
             click.secho(message, fg="red", err=True)
             sys.exit(1)
 
-    add_ons_str = add_ons_str.lower()
-    if add_ons_str == "all":
-        return list(NUMBER_TO_ADD_ONS_NAME)
-    if add_ons_str == "none":
+    tools_str = tools_str.lower()
+    if tools_str == "all":
+        return list(NUMBER_TO_TOOLS_NAME)
+    if tools_str == "none":
         return []
-    # Guard clause if add_ons_str is None, which can happen if prompts.yml is removed
-    if not add_ons_str:
+    # Guard clause if tools_str is None, which can happen if prompts.yml is removed
+    if not tools_str:
         return []  # pragma: no cover
 
     # Split by comma
-    add_ons_choices = add_ons_str.replace(" ", "").split(",")
+    tools_choices = tools_str.replace(" ", "").split(",")
     selected: list[str] = []
 
-    for choice in add_ons_choices:
+    for choice in tools_choices:
         if "-" in choice:
             start, end = choice.split("-")
             _validate_range(start, end)
@@ -830,34 +830,28 @@ def _create_project(template_path: str, cookiecutter_args: dict[str, Any]):
     _clean_pycache(Path(result_path))
     extra_context = cookiecutter_args["extra_context"]
     project_name = extra_context.get("project_name", "New Kedro Project")
-    python_package = extra_context.get(
-        "python_package", project_name.lower().replace(" ", "_").replace("-", "_")
+    tools = extra_context.get("tools")
+    example_pipeline = extra_context.get("example_pipeline")
+
+    click.secho(
+        "\nCongratulations!"
+        f"\nYour project '{project_name}' has been created in the directory \n{result_path}"
     )
-    add_ons = extra_context.get("add_ons")
 
-    # we can use starters without add_ons:
-    if add_ons is not None:
-        if add_ons == "[]":  # TODO: This should be a list
-            click.secho("\nYou have selected no add-ons")
+    # we can use starters without tools:
+    if tools is not None:
+        if tools == "[]":  # TODO: This should be a list
+            click.secho("You have selected no tools")
         else:
-            click.secho(f"\nYou have selected the following add-ons: {add_ons}")
+            click.secho(f"You have selected the following tools: {tools}")
+
+    if example_pipeline is not None:
+        if example_pipeline:
+            click.secho("It has been created with an example pipeline.")
 
     click.secho(
-        f"\nThe project name '{project_name}' has been applied to: "
-        f"\n- The project title in {result_path}/README.md "
-        f"\n- The folder created for your project in {result_path} "
-        f"\n- The project's python package in {result_path}/src/{python_package}"
-    )
-    click.secho(
-        "\nA best-practice setup includes initialising git and creating "
-        "a virtual environment before running 'pip install -r requirements.txt' to install "
-        "project-specific dependencies. Refer to the Kedro documentation: "
-        "https://kedro.readthedocs.io/"
-    )
-    click.secho(
-        f"\nChange directory to the project generated in {result_path} by "
-        f"entering 'cd {result_path}'",
-        fg="green",
+        "\nTo skip the interactive flow you can run `kedro new` with"
+        "\nkedro new --name=<your-project-name> --tools=<your-project-tools> --example=<yes/no>"
     )
 
 
@@ -892,9 +886,9 @@ def validate(self, user_input: str) -> None:
             click.secho(self.error_message, fg="red", err=True)
             sys.exit(1)
 
-        if self.title == "Project Add-Ons":
+        if self.title == "Project Tools":
             # Validate user input
-            _validate_selection(_parse_add_ons_input(user_input))
+            _validate_selection(_parse_tools_input(user_input))
 
 
 # noqa: unused-argument
diff --git a/kedro/framework/startup.py b/kedro/framework/startup.py
index 1ebb594588..c063eb630c 100644
--- a/kedro/framework/startup.py
+++ b/kedro/framework/startup.py
@@ -21,7 +21,7 @@ class ProjectMetadata(NamedTuple):
     project_path: Path
     source_dir: Path
     kedro_init_version: str
-    add_ons: list
+    tools: list
 
 
 def _version_mismatch_error(kedro_init_version) -> str:
@@ -102,7 +102,7 @@ def _get_project_metadata(project_path: Union[str, Path]) -> ProjectMetadata:
     # Default settings
     source_dir = Path(metadata_dict.get("source_dir", "src")).expanduser()
     source_dir = (project_path / source_dir).resolve()
-    metadata_dict["add_ons"] = metadata_dict.get("add_ons")
+    metadata_dict["tools"] = metadata_dict.get("tools")
 
     metadata_dict["source_dir"] = source_dir
     metadata_dict["config_file"] = pyproject_toml
diff --git a/kedro/templates/project/cookiecutter.json b/kedro/templates/project/cookiecutter.json
index 61c308af96..9152bad722 100644
--- a/kedro/templates/project/cookiecutter.json
+++ b/kedro/templates/project/cookiecutter.json
@@ -3,6 +3,6 @@
     "repo_name": "{{ cookiecutter.project_name.strip().replace(' ', '-').replace('_', '-').lower() }}",
     "python_package": "{{ cookiecutter.project_name.strip().replace(' ', '_').replace('-', '_').lower() }}",
     "kedro_version": "{{ cookiecutter.kedro_version }}",
-    "add_ons": "none",
+    "tools": "none",
     "example_pipeline": "no"
 }
diff --git a/kedro/templates/project/hooks/post_gen_project.py b/kedro/templates/project/hooks/post_gen_project.py
index 22e1629be2..cb372b7339 100644
--- a/kedro/templates/project/hooks/post_gen_project.py
+++ b/kedro/templates/project/hooks/post_gen_project.py
@@ -2,7 +2,7 @@
 
 from kedro.templates.project.hooks.utils import (
 
-    setup_template_add_ons,
+    setup_template_tools,
     sort_requirements,
 )
 
@@ -13,12 +13,12 @@ def main():
     pyproject_file_path = current_dir / "pyproject.toml"
     python_package_name = '{{ cookiecutter.python_package }}'
 
-    # Get the selected add-ons from cookiecutter
-    selected_add_ons = "{{ cookiecutter.add_ons }}"
+    # Get the selected toolss from cookiecutter
+    selected_tools = "{{ cookiecutter.tools }}"
     example_pipeline = "{{ cookiecutter.example_pipeline }}"
 
-    # Handle template directories and requirements according to selected add-ons
-    setup_template_add_ons(selected_add_ons, requirements_file_path, pyproject_file_path, python_package_name, example_pipeline)
+    # Handle template directories and requirements according to selected tools
+    setup_template_tools(selected_tools, requirements_file_path, pyproject_file_path, python_package_name, example_pipeline)
 
     # Sort requirements.txt file in alphabetical order
     sort_requirements(requirements_file_path)
diff --git a/kedro/templates/project/hooks/utils.py b/kedro/templates/project/hooks/utils.py
index 3ea4db22fe..c0c5de47c7 100644
--- a/kedro/templates/project/hooks/utils.py
+++ b/kedro/templates/project/hooks/utils.py
@@ -141,37 +141,37 @@ def _remove_pyspark_viz_starter_files(is_viz: bool, python_package_name: str) ->
     _remove_file(test_pipeline_path)
 
 
-def setup_template_add_ons(selected_add_ons_list: str, requirements_file_path: str, pyproject_file_path: str, python_package_name: str, example_pipeline: str) -> None:
-    """Setup the templates according to the choice of add-ons.
+def setup_template_tools(selected_tools_list: str, requirements_file_path: str, pyproject_file_path: str, python_package_name: str, example_pipeline: str) -> None:
+    """Setup the templates according to the choice of tools.
 
     Args:
-        selected_add_ons_list (str): A string contains the selected add-ons.
+        selected_tools_list (str): A string contains the selected tools.
         requirements_file_path (str): The path of the `requiremenets.txt` in the template.
         pyproject_file_path (str): The path of the `pyproject.toml` in the template
         python_package_name (str): The name of the python package.
         example_pipeline (str): 'True' if example pipeline was selected
     """
-    if "Linting" not in selected_add_ons_list:
+    if "Linting" not in selected_tools_list:
         _remove_from_file(requirements_file_path, lint_requirements)
         _remove_from_toml(pyproject_file_path, lint_pyproject_requirements)
 
-    if "Testing" not in selected_add_ons_list:
+    if "Testing" not in selected_tools_list:
         _remove_from_file(requirements_file_path, test_requirements)
         _remove_from_toml(pyproject_file_path, test_pyproject_requirements)
         _remove_dir(current_dir / "tests")
 
-    if "Logging" not in selected_add_ons_list:
+    if "Logging" not in selected_tools_list:
         _remove_file(current_dir / "conf/logging.yml")
 
-    if "Documentation" not in selected_add_ons_list:
+    if "Documentation" not in selected_tools_list:
         _remove_from_toml(pyproject_file_path, docs_pyproject_requirements)
         _remove_dir(current_dir / "docs")
 
-    if "Data Structure" not in selected_add_ons_list and example_pipeline != "True":
+    if "Data Structure" not in selected_tools_list and example_pipeline != "True":
         _remove_dir(current_dir / "data")
 
-    if ("Pyspark" in selected_add_ons_list or "Kedro Viz" in selected_add_ons_list) and example_pipeline != "True":
-        _remove_pyspark_viz_starter_files("Kedro Viz" in selected_add_ons_list, python_package_name)
+    if ("Pyspark" in selected_tools_list or "Kedro Viz" in selected_tools_list) and example_pipeline != "True":
+        _remove_pyspark_viz_starter_files("Kedro Viz" in selected_tools_list, python_package_name)
 
 
 def sort_requirements(requirements_file_path: Path) -> None:
diff --git a/kedro/templates/project/prompts.yml b/kedro/templates/project/prompts.yml
index 9c9fa67faa..fd6e3991a2 100644
--- a/kedro/templates/project/prompts.yml
+++ b/kedro/templates/project/prompts.yml
@@ -1,40 +1,43 @@
-add_ons:
-  title: "Project Add-Ons"
-  text: |
-    Here you can select which add-ons you'd like to include. By default, none are included.
-    To read more about these add-ons and what they do visit: kedro.org/{insert-documentation}
-
-    Add-Ons
-    1) Linting : Provides a basic linting set up with Black and ruff
-    2) Testing : Provides basic testing set up with pytest
-    3) Custom Logging : Provides more logging options
-    4) Documentation: Provides basic documentations setup with Sphinx
-    5) Data Structure: Provides a directory structure for storing data
-    6) Pyspark: Provides set up configuration for working with PySpark
-    7) Kedro Viz: Provides Kedro's native visualisation tool
-
-    Which add-ons would you like to include in your project? [1-7/1,3/all/none]:
-  regex_validator: "^(all|none|(( )*\\d*(,\\d*)*(,( )*\\d*)*( )*|( )*((\\d+-\\d+)|(\\d+ - \\d+))( )*))$"
-  error_message: |
-    Invalid input. Please select valid options for add-ons using comma-separated values, ranges, or 'all/none'.
-
 project_name:
   title: "Project Name"
   text: |
-    Please enter a human readable name for your new project.
+    Please enter a name for your new project.
     Spaces, hyphens, and underscores are allowed.
+    To skip this step in future use --name
   regex_validator: "^[\\w -]{2,}$"
   error_message: |
     It must contain only alphanumeric symbols, spaces, underscores and hyphens and
     be at least 2 characters long.
 
+tools:
+  title: "Project Tools"
+  text: |
+    These optional tools can help you apply software engineering best practices.
+    To skip this step in future use --tools
+    To find out more: kedro.org/ # TODO - add docs link in #3048
+
+    Tools
+    1) Lint: Basic linting with Black and Ruff
+    2) Test: Basic testing with pytest
+    3) Log: Additional, environment-specific logging options
+    4) Docs: A Sphinx documentation setup
+    5) Data Folder: A folder structure for data management
+    6) PySpark: Configuration for working with PySpark
+    7) Kedro-Viz: Kedro's native visualisation tool
+
+    Which tools would you like to include in your project? [1-7/1,3/all/none]:
+  regex_validator: "^(all|none|(( )*\\d*(,\\d*)*(,( )*\\d*)*( )*|( )*((\\d+-\\d+)|(\\d+ - \\d+))( )*))$"
+  error_message: |
+    Invalid input. Please select valid options for tools using comma-separated values, ranges, or 'all/none'.
+
 example_pipeline:
   title: "Example Pipeline"
   text: |
     Select whether you would like an example spaceflights pipeline included in your project.
     To skip this step in the future use --example=y/n
-    To read more about how examples work visit: kedro.org/
-    Would you like to include an example pipeline? \[y/N]:
+    To find out more: kedro.org/ # TODO - add docs link in #3048
+
+    Would you like to include an example pipeline? [y/N]:
   regex_validator: "(?i)^(y|yes|n|no)$"
   error_message: |
     It must contain only y, n, YES, NO, case insensitive.
diff --git a/kedro/templates/project/{{ cookiecutter.repo_name }}/pyproject.toml b/kedro/templates/project/{{ cookiecutter.repo_name }}/pyproject.toml
index 92810db841..07592a3276 100644
--- a/kedro/templates/project/{{ cookiecutter.repo_name }}/pyproject.toml	
+++ b/kedro/templates/project/{{ cookiecutter.repo_name }}/pyproject.toml	
@@ -37,7 +37,7 @@ namespaces = false
 package_name = "{{ cookiecutter.python_package }}"
 project_name = "{{ cookiecutter.project_name }}"
 kedro_init_version = "{{ cookiecutter.kedro_version }}"
-add_ons = "{{ cookiecutter.add_ons | default('') | string | replace('\"', '\\\"') }}"
+tools = "{{ cookiecutter.tools | default('') | string | replace('\"', '\\\"') }}"
 
 [tool.pytest.ini_options]
 addopts = """
diff --git a/tests/framework/cli/conftest.py b/tests/framework/cli/conftest.py
index da5cf6d046..a151136092 100644
--- a/tests/framework/cli/conftest.py
+++ b/tests/framework/cli/conftest.py
@@ -88,7 +88,7 @@ def fake_metadata(fake_root_dir):
         project_path=fake_root_dir / REPO_NAME,
         kedro_init_version=kedro_version,
         source_dir=fake_root_dir / REPO_NAME / "src",
-        add_ons=None,
+        tools=None,
     )
     return metadata
 
diff --git a/tests/framework/cli/test_starters.py b/tests/framework/cli/test_starters.py
index cc73c0e022..af82f3a5c7 100644
--- a/tests/framework/cli/test_starters.py
+++ b/tests/framework/cli/test_starters.py
@@ -16,13 +16,13 @@
     _OFFICIAL_STARTER_SPECS,
     TEMPLATE_PATH,
     KedroStarterSpec,
-    _convert_addon_names_to_numbers,
-    _parse_add_ons_input,
+    _convert_tools_names_to_numbers,
+    _parse_tools_input,
     _parse_yes_no_to_bool,
     _validate_selection,
 )
 
-FILES_IN_TEMPLATE_WITH_NO_ADD_ONS = 15
+FILES_IN_TEMPLATE_WITH_NO_TOOLS = 15
 
 
 @pytest.fixture
@@ -55,31 +55,31 @@ def _write_yaml(filepath: Path, config: dict):
 
 
 def _make_cli_prompt_input(
-    add_ons="none",
+    tools="none",
     project_name="",
     example_pipeline="no",
     repo_name="",
     python_package="",
 ):
     return "\n".join(
-        [add_ons, project_name, example_pipeline, repo_name, python_package]
+        [project_name, tools, example_pipeline, repo_name, python_package]
     )
 
 
-def _make_cli_prompt_input_without_addons(
+def _make_cli_prompt_input_without_tools(
     project_name="", repo_name="", python_package=""
 ):
     return "\n".join([project_name, repo_name, python_package])
 
 
 def _make_cli_prompt_input_without_name(
-    add_ons="none", repo_name="", python_package=""
+    tools="none", repo_name="", python_package=""
 ):
-    return "\n".join([add_ons, repo_name, python_package])
+    return "\n".join([tools, repo_name, python_package])
 
 
-def _get_expected_files(add_ons: str, example_pipeline: str):
-    add_ons_template_files = {
+def _get_expected_files(tools: str, example_pipeline: str):
+    tools_template_files = {
         "1": 0,  # Linting does not add any files
         "2": 3,  # If Testing is selected, we add 2 init.py files and 1 test_run.py
         "3": 1,  # If Logging is selected, we add logging.py
@@ -87,16 +87,16 @@ def _get_expected_files(add_ons: str, example_pipeline: str):
         "5": 8,  # If Data Structure is selected, we add 8 .gitkeep files
         "6": 2,  # If Pyspark is selected, we add spark.yml and hooks.py
         "7": 0,  # Kedro Viz does not add any files
-    }  # files added to template by each add-on
-    add_ons_list = _parse_add_ons_input(add_ons)
+    }  # files added to template by each tool
+    tools_list = _parse_tools_input(tools)
     example_pipeline_bool = _parse_yes_no_to_bool(example_pipeline)
-    expected_files = FILES_IN_TEMPLATE_WITH_NO_ADD_ONS
+    expected_files = FILES_IN_TEMPLATE_WITH_NO_TOOLS
 
-    for add_on in add_ons_list:
-        expected_files = expected_files + add_ons_template_files[add_on]
+    for tool in tools_list:
+        expected_files = expected_files + tools_template_files[tool]
     # If example pipeline was chosen we don't need to delete /data folder
-    if example_pipeline_bool and "5" not in add_ons_list:
-        expected_files += add_ons_template_files["5"]
+    if example_pipeline_bool and "5" not in tools_list:
+        expected_files += tools_template_files["5"]
     example_files_count = [
         3,  # Raw data files
         2,  # Parameters_ .yml files
@@ -105,31 +105,34 @@ def _get_expected_files(add_ons: str, example_pipeline: str):
     if example_pipeline_bool:  # If example option is chosen
         expected_files += sum(example_files_count)
         expected_files += (
-            4 if "7" in add_ons_list else 0
+            4 if "7" in tools_list else 0
         )  # add 3 .py and 1 parameters files in reporting for Viz
         expected_files += (
-            1 if "2" in add_ons_list else 0
-        )  # add 1 test file if tests is chosen in add_ons
+            1 if "2" in tools_list else 0
+        )  # add 1 test file if tests is chosen in tools
 
     return expected_files
 
 
 def _assert_requirements_ok(
     result,
-    add_ons="none",
+    tools="none",
     repo_name="new-kedro-project",
     output_dir=".",
 ):
     assert result.exit_code == 0, result.output
-    assert "Change directory to the project generated in" in result.output
 
     root_path = (Path(output_dir) / repo_name).resolve()
+
+    assert "Congratulations!" in result.output
+    assert f"has been created in the directory \n{root_path}" in result.output
+
     requirements_file_path = root_path / "requirements.txt"
     pyproject_file_path = root_path / "pyproject.toml"
 
-    add_ons_list = _parse_add_ons_input(add_ons)
+    tools_list = _parse_tools_input(tools)
 
-    if "1" in add_ons_list:
+    if "1" in tools_list:
         with open(requirements_file_path) as requirements_file:
             requirements = requirements_file.read()
 
@@ -149,7 +152,7 @@ def _assert_requirements_ok(
         }
         assert expected["tool"]["ruff"] == pyproject_config["tool"]["ruff"]
 
-    if "2" in add_ons_list:
+    if "2" in tools_list:
         with open(requirements_file_path) as requirements_file:
             requirements = requirements_file.read()
 
@@ -175,7 +178,7 @@ def _assert_requirements_ok(
         assert expected["pytest"] == pyproject_config["tool"]["pytest"]
         assert expected["coverage"] == pyproject_config["tool"]["coverage"]
 
-    if "4" in add_ons_list:
+    if "4" in tools_list:
         pyproject_config = toml.load(pyproject_file_path)
         expected = {
             "optional-dependencies": {
@@ -201,7 +204,7 @@ def _assert_requirements_ok(
 # noqa: PLR0913
 def _assert_template_ok(
     result,
-    add_ons="none",
+    tools="none",
     project_name="New Kedro Project",
     example_pipeline="no",
     repo_name="new-kedro-project",
@@ -210,14 +213,23 @@ def _assert_template_ok(
     output_dir=".",
 ):
     assert result.exit_code == 0, result.output
-    assert "Change directory to the project generated in" in result.output
 
     full_path = (Path(output_dir) / repo_name).resolve()
+
+    assert "Congratulations!" in result.output
+    assert (
+        f"Your project '{project_name}' has been created in the directory \n{full_path}"
+        in result.output
+    )
+
+    if "y" in example_pipeline.lower():
+        assert "It has been created with an example pipeline." in result.output
+
     generated_files = [
         p for p in full_path.rglob("*") if p.is_file() and p.name != ".DS_Store"
     ]
 
-    assert len(generated_files) == _get_expected_files(add_ons, example_pipeline)
+    assert len(generated_files) == _get_expected_files(tools, example_pipeline)
     assert full_path.exists()
     assert (full_path / ".gitignore").is_file()
     assert project_name in (full_path / "README.md").read_text(encoding="utf-8")
@@ -231,9 +243,10 @@ def _assert_name_ok(
     project_name="New Kedro Project",
 ):
     assert result.exit_code == 0, result.output
-    assert "Change directory to the project generated in" in result.output
+    assert "Congratulations!" in result.output
     assert (
-        "The project name '" + project_name + "' has been applied to: " in result.output
+        f"Your project '{project_name}' has been created in the directory"
+        in result.output
     )
 
 
@@ -293,8 +306,8 @@ def test_starter_list_with_invalid_starter_plugin(
         ("none", []),
     ],
 )
-def test_parse_add_ons_valid(input, expected):
-    result = _parse_add_ons_input(input)
+def test_parse_tools_valid(input, expected):
+    result = _parse_tools_input(input)
     assert result == expected
 
 
@@ -302,10 +315,10 @@ def test_parse_add_ons_valid(input, expected):
     "input",
     ["5-2", "3-1"],
 )
-def test_parse_add_ons_invalid_range(input, capsys):
+def test_parse_tools_invalid_range(input, capsys):
     with pytest.raises(SystemExit):
-        _parse_add_ons_input(input)
-    message = f"'{input}' is an invalid range for project add-ons.\nPlease ensure range values go from smaller to larger."
+        _parse_tools_input(input)
+    message = f"'{input}' is an invalid range for project tools.\nPlease ensure range values go from smaller to larger."
     assert message in capsys.readouterr().err
 
 
@@ -313,11 +326,11 @@ def test_parse_add_ons_invalid_range(input, capsys):
     "input,last_invalid",
     [("0,3,5", "0"), ("1,3,8", "8"), ("0-4", "0"), ("3-9", "9")],
 )
-def test_parse_add_ons_invalid_selection(input, last_invalid, capsys):
+def test_parse_tools_invalid_selection(input, last_invalid, capsys):
     with pytest.raises(SystemExit):
-        selected = _parse_add_ons_input(input)
+        selected = _parse_tools_input(input)
         _validate_selection(selected)
-    message = f"'{last_invalid}' is not a valid selection.\nPlease select from the available add-ons: 1, 2, 3, 4, 5, 6, 7."
+    message = f"'{last_invalid}' is not a valid selection.\nPlease select from the available tools: 1, 2, 3, 4, 5, 6, 7."
     assert message in capsys.readouterr().err
 
 
@@ -511,7 +524,7 @@ class TestNewFromConfigFileValid:
     def test_required_keys_only(self, fake_kedro_cli):
         """Test project created from config."""
         config = {
-            "add_ons": "none",
+            "tools": "none",
             "project_name": "My Project",
             "example_pipeline": "no",
             "repo_name": "my-project",
@@ -527,7 +540,7 @@ def test_required_keys_only(self, fake_kedro_cli):
     def test_custom_required_keys(self, fake_kedro_cli):
         """Test project created from config."""
         config = {
-            "add_ons": "none",
+            "tools": "none",
             "project_name": "Project X",
             "example_pipeline": "no",
             "repo_name": "projectx",
@@ -543,7 +556,7 @@ def test_custom_required_keys(self, fake_kedro_cli):
     def test_custom_kedro_version(self, fake_kedro_cli):
         """Test project created from config."""
         config = {
-            "add_ons": "none",
+            "tools": "none",
             "project_name": "My Project",
             "example_pipeline": "no",
             "repo_name": "my-project",
@@ -560,7 +573,7 @@ def test_custom_kedro_version(self, fake_kedro_cli):
     def test_custom_output_dir(self, fake_kedro_cli):
         """Test project created from config."""
         config = {
-            "add_ons": "none",
+            "tools": "none",
             "project_name": "My Project",
             "example_pipeline": "no",
             "repo_name": "my-project",
@@ -578,7 +591,7 @@ def test_custom_output_dir(self, fake_kedro_cli):
     def test_extra_keys_allowed(self, fake_kedro_cli):
         """Test project created from config."""
         config = {
-            "add_ons": "none",
+            "tools": "none",
             "project_name": "My Project",
             "example_pipeline": "no",
             "repo_name": "my-project",
@@ -627,7 +640,7 @@ class TestNewFromConfigFileInvalid:
     def test_output_dir_does_not_exist(self, fake_kedro_cli):
         """Check the error if the output directory is invalid."""
         config = {
-            "add_ons": "none",
+            "tools": "none",
             "project_name": "My Project",
             "example_pipeline": "no",
             "repo_name": "my-project",
@@ -642,7 +655,7 @@ def test_output_dir_does_not_exist(self, fake_kedro_cli):
     def test_config_missing_key(self, fake_kedro_cli):
         """Check the error if keys are missing from config file."""
         config = {
-            "add_ons": "none",
+            "tools": "none",
             "example_pipeline": "no",
             "python_package": "my_project",
             "repo_name": "my-project",
@@ -674,7 +687,7 @@ def test_config_bad_yaml(self, fake_kedro_cli):
 
     def test_invalid_project_name_special_characters(self, fake_kedro_cli):
         config = {
-            "add_ons": "none",
+            "tools": "none",
             "project_name": "My $Project!",
             "example_pipeline": "no",
             "repo_name": "my-project",
@@ -693,7 +706,7 @@ def test_invalid_project_name_special_characters(self, fake_kedro_cli):
 
     def test_invalid_project_name_too_short(self, fake_kedro_cli):
         config = {
-            "add_ons": "none",
+            "tools": "none",
             "project_name": "P",
             "example_pipeline": "no",
             "repo_name": "my-project",
@@ -908,9 +921,9 @@ def test_directory_flag_with_starter_alias(self, fake_kedro_cli):
 
 
 @pytest.mark.usefixtures("chdir_to_tmp")
-class TestAddOnsAndExampleFromUserPrompts:
+class TestToolsAndExampleFromUserPrompts:
     @pytest.mark.parametrize(
-        "add_ons",
+        "tools",
         [
             "1",
             "2",
@@ -929,34 +942,34 @@ class TestAddOnsAndExampleFromUserPrompts:
         ],
     )
     @pytest.mark.parametrize("example_pipeline", ["Yes", "No"])
-    def test_valid_add_ons_and_example(self, fake_kedro_cli, add_ons, example_pipeline):
+    def test_valid_tools_and_example(self, fake_kedro_cli, tools, example_pipeline):
         result = CliRunner().invoke(
             fake_kedro_cli,
             ["new"],
             input=_make_cli_prompt_input(
-                add_ons=add_ons, example_pipeline=example_pipeline
+                tools=tools, example_pipeline=example_pipeline
             ),
         )
 
-        _assert_template_ok(result, add_ons=add_ons, example_pipeline=example_pipeline)
-        _assert_requirements_ok(result, add_ons=add_ons)
+        _assert_template_ok(result, tools=tools, example_pipeline=example_pipeline)
+        _assert_requirements_ok(result, tools=tools)
         _clean_up_project(Path("./new-kedro-project"))
 
     @pytest.mark.parametrize(
         "bad_input",
         ["bad input", "-1", "3-"],
     )
-    def test_invalid_add_ons(self, fake_kedro_cli, bad_input):
+    def test_invalid_tools(self, fake_kedro_cli, bad_input):
         result = CliRunner().invoke(
             fake_kedro_cli,
             ["new"],
-            input=_make_cli_prompt_input(add_ons=bad_input),
+            input=_make_cli_prompt_input(tools=bad_input),
         )
 
         assert result.exit_code != 0
-        assert "is an invalid value for project add-ons." in result.output
+        assert "is an invalid value for project tools." in result.output
         assert (
-            "Invalid input. Please select valid options for add-ons using comma-separated values, ranges, or 'all/none'.\n"
+            "Invalid input. Please select valid options for tools using comma-separated values, ranges, or 'all/none'.\n"
             in result.output
         )
 
@@ -964,30 +977,30 @@ def test_invalid_add_ons(self, fake_kedro_cli, bad_input):
         "input,last_invalid",
         [("0,3,5", "0"), ("1,3,9", "9"), ("0-4", "0"), ("3-9", "9"), ("99", "99")],
     )
-    def test_invalid_add_ons_selection(self, fake_kedro_cli, input, last_invalid):
+    def test_invalid_tools_selection(self, fake_kedro_cli, input, last_invalid):
         result = CliRunner().invoke(
             fake_kedro_cli,
             ["new"],
-            input=_make_cli_prompt_input(add_ons=input),
+            input=_make_cli_prompt_input(tools=input),
         )
 
         assert result.exit_code != 0
-        message = f"'{last_invalid}' is not a valid selection.\nPlease select from the available add-ons: 1, 2, 3, 4, 5, 6, 7."
+        message = f"'{last_invalid}' is not a valid selection.\nPlease select from the available tools: 1, 2, 3, 4, 5, 6, 7."
         assert message in result.output
 
     @pytest.mark.parametrize(
         "input",
         ["5-2", "3-1"],
     )
-    def test_invalid_add_ons_range(self, fake_kedro_cli, input):
+    def test_invalid_tools_range(self, fake_kedro_cli, input):
         result = CliRunner().invoke(
             fake_kedro_cli,
             ["new"],
-            input=_make_cli_prompt_input(add_ons=input),
+            input=_make_cli_prompt_input(tools=input),
         )
 
         assert result.exit_code != 0
-        message = f"'{input}' is an invalid range for project add-ons.\nPlease ensure range values go from smaller to larger."
+        message = f"'{input}' is an invalid range for project tools.\nPlease ensure range values go from smaller to larger."
         assert message in result.output
 
     @pytest.mark.parametrize("example_pipeline", ["y", "n", "N", "YEs", "    yeS   "])
@@ -1020,9 +1033,9 @@ def test_invalid_example(self, fake_kedro_cli, bad_input):
 
 
 @pytest.mark.usefixtures("chdir_to_tmp")
-class TestAddOnsAndExampleFromConfigFile:
+class TestToolsAndExampleFromConfigFile:
     @pytest.mark.parametrize(
-        "add_ons",
+        "tools",
         [
             "1",
             "2",
@@ -1041,10 +1054,10 @@ class TestAddOnsAndExampleFromConfigFile:
         ],
     )
     @pytest.mark.parametrize("example_pipeline", ["Yes", "No"])
-    def test_valid_add_ons_and_example(self, fake_kedro_cli, add_ons, example_pipeline):
+    def test_valid_tools_and_example(self, fake_kedro_cli, tools, example_pipeline):
         """Test project created from config."""
         config = {
-            "add_ons": add_ons,
+            "tools": tools,
             "project_name": "New Kedro Project",
             "example_pipeline": example_pipeline,
             "repo_name": "new-kedro-project",
@@ -1056,17 +1069,17 @@ def test_valid_add_ons_and_example(self, fake_kedro_cli, add_ons, example_pipeli
         )
 
         _assert_template_ok(result, **config)
-        _assert_requirements_ok(result, add_ons=add_ons, repo_name="new-kedro-project")
+        _assert_requirements_ok(result, tools=tools, repo_name="new-kedro-project")
         _clean_up_project(Path("./new-kedro-project"))
 
     @pytest.mark.parametrize(
         "bad_input",
         ["bad input", "-1", "3-"],
     )
-    def test_invalid_add_ons(self, fake_kedro_cli, bad_input):
+    def test_invalid_tools(self, fake_kedro_cli, bad_input):
         """Test project created from config."""
         config = {
-            "add_ons": bad_input,
+            "tools": bad_input,
             "project_name": "My Project",
             "example_pipeline": "no",
             "repo_name": "my-project",
@@ -1078,9 +1091,9 @@ def test_invalid_add_ons(self, fake_kedro_cli, bad_input):
         )
 
         assert result.exit_code != 0
-        assert "is an invalid value for project add-ons." in result.output
+        assert "is an invalid value for project tools." in result.output
         assert (
-            "Please select valid options for add-ons using comma-separated values, ranges, or 'all/none'.\n"
+            "Please select valid options for tools using comma-separated values, ranges, or 'all/none'.\n"
             in result.output
         )
 
@@ -1088,9 +1101,9 @@ def test_invalid_add_ons(self, fake_kedro_cli, bad_input):
         "input,last_invalid",
         [("0,3,5", "0"), ("1,3,9", "9"), ("0-4", "0"), ("3-9", "9"), ("99", "99")],
     )
-    def test_invalid_add_ons_selection(self, fake_kedro_cli, input, last_invalid):
+    def test_invalid_tools_selection(self, fake_kedro_cli, input, last_invalid):
         config = {
-            "add_ons": input,
+            "tools": input,
             "project_name": "My Project",
             "example_pipeline": "no",
             "repo_name": "my-project",
@@ -1102,16 +1115,16 @@ def test_invalid_add_ons_selection(self, fake_kedro_cli, input, last_invalid):
         )
 
         assert result.exit_code != 0
-        message = f"'{last_invalid}' is not a valid selection.\nPlease select from the available add-ons: 1, 2, 3, 4, 5, 6, 7."
+        message = f"'{last_invalid}' is not a valid selection.\nPlease select from the available tools: 1, 2, 3, 4, 5, 6, 7."
         assert message in result.output
 
     @pytest.mark.parametrize(
         "input",
         ["5-2", "3-1"],
     )
-    def test_invalid_add_ons_range(self, fake_kedro_cli, input):
+    def test_invalid_tools_range(self, fake_kedro_cli, input):
         config = {
-            "add_ons": input,
+            "tools": input,
             "project_name": "My Project",
             "example_pipeline": "no",
             "repo_name": "my-project",
@@ -1123,14 +1136,14 @@ def test_invalid_add_ons_range(self, fake_kedro_cli, input):
         )
 
         assert result.exit_code != 0
-        message = f"'{input}' is an invalid range for project add-ons.\nPlease ensure range values go from smaller to larger."
+        message = f"'{input}' is an invalid range for project tools.\nPlease ensure range values go from smaller to larger."
         assert message in result.output
 
     @pytest.mark.parametrize("example_pipeline", ["y", "n", "N", "YEs", "    yeS   "])
     def test_valid_example(self, fake_kedro_cli, example_pipeline):
         """Test project created from config."""
         config = {
-            "add_ons": "none",
+            "tools": "none",
             "project_name": "New Kedro Project",
             "example_pipeline": example_pipeline,
             "repo_name": "new-kedro-project",
@@ -1151,7 +1164,7 @@ def test_valid_example(self, fake_kedro_cli, example_pipeline):
     def test_invalid_example(self, fake_kedro_cli, bad_input):
         """Test project created from config."""
         config = {
-            "add_ons": "none",
+            "tools": "none",
             "project_name": "My Project",
             "example_pipeline": bad_input,
             "repo_name": "my-project",
@@ -1169,9 +1182,9 @@ def test_invalid_example(self, fake_kedro_cli, bad_input):
 
 
 @pytest.mark.usefixtures("chdir_to_tmp")
-class TestAddOnsAndExampleFromCLI:
+class TestToolsAndExampleFromCLI:
     @pytest.mark.parametrize(
-        "add_ons",
+        "tools",
         [
             "lint",
             "test",
@@ -1195,44 +1208,44 @@ class TestAddOnsAndExampleFromCLI:
         ],
     )
     @pytest.mark.parametrize("example_pipeline", ["Yes", "No"])
-    def test_valid_add_ons_flag(self, fake_kedro_cli, add_ons, example_pipeline):
+    def test_valid_tools_flag(self, fake_kedro_cli, tools, example_pipeline):
         result = CliRunner().invoke(
             fake_kedro_cli,
-            ["new", "--addons", add_ons, "--example", example_pipeline],
-            input=_make_cli_prompt_input_without_addons(),
+            ["new", "--tools", tools, "--example", example_pipeline],
+            input=_make_cli_prompt_input_without_tools(),
         )
-        add_ons = _convert_addon_names_to_numbers(selected_add_ons_flag=add_ons)
-        _assert_template_ok(result, add_ons=add_ons, example_pipeline=example_pipeline)
-        _assert_requirements_ok(result, add_ons=add_ons, repo_name="new-kedro-project")
+        tools = _convert_tools_names_to_numbers(selected_tools=tools)
+        _assert_template_ok(result, tools=tools, example_pipeline=example_pipeline)
+        _assert_requirements_ok(result, tools=tools, repo_name="new-kedro-project")
         _clean_up_project(Path("./new-kedro-project"))
 
-    def test_invalid_add_ons_flag(self, fake_kedro_cli):
+    def test_invalid_tools_flag(self, fake_kedro_cli):
         result = CliRunner().invoke(
             fake_kedro_cli,
-            ["new", "--addons", "bad_input"],
-            input=_make_cli_prompt_input_without_addons(),
+            ["new", "--tools", "bad_input"],
+            input=_make_cli_prompt_input_without_tools(),
         )
 
         assert result.exit_code != 0
         assert (
-            "Please select from the available add-ons: lint, test, log, docs, data, pyspark, viz, all, none"
+            "Please select from the available tools: lint, test, log, docs, data, pyspark, viz, all, none"
             in result.output
         )
 
     @pytest.mark.parametrize(
-        "add_ons",
+        "tools",
         ["lint,all", "test,none", "all,none"],
     )
-    def test_invalid_add_ons_flag_combination(self, fake_kedro_cli, add_ons):
+    def test_invalid_tools_flag_combination(self, fake_kedro_cli, tools):
         result = CliRunner().invoke(
             fake_kedro_cli,
-            ["new", "--addons", add_ons],
-            input=_make_cli_prompt_input_without_addons(),
+            ["new", "--tools", tools],
+            input=_make_cli_prompt_input_without_tools(),
         )
 
         assert result.exit_code != 0
         assert (
-            "Add-on options 'all' and 'none' cannot be used with other options"
+            "Tools options 'all' and 'none' cannot be used with other options"
             in result.output
         )
 
diff --git a/tests/framework/test_startup.py b/tests/framework/test_startup.py
index 2edc34e8be..145ee824ec 100644
--- a/tests/framework/test_startup.py
+++ b/tests/framework/test_startup.py
@@ -94,7 +94,7 @@ def test_valid_toml_file(self, mocker):
             project_name="fake_project_name",
             kedro_init_version=kedro_version,
             project_path=self.project_path,
-            add_ons=None,
+            tools=None,
         )
         assert actual == expected
 
@@ -121,7 +121,7 @@ def test_valid_toml_file_with_project_version(self, mocker):
             project_name="fake_project_name",
             kedro_init_version=kedro_version,
             project_path=self.project_path,
-            add_ons=None,
+            tools=None,
         )
         assert actual == expected
 
@@ -300,7 +300,7 @@ def test_bootstrap_project(self, monkeypatch, tmp_path):
             "project_path": tmp_path,
             "kedro_init_version": kedro_version,
             "source_dir": src_dir,
-            "add_ons": None,
+            "tools": None,
         }
         assert result == ProjectMetadata(**expected_metadata)
         assert str(src_dir) in sys.path[0]
diff --git a/tests/ipython/test_ipython.py b/tests/ipython/test_ipython.py
index 2e3c59fce5..ac5bfe9153 100644
--- a/tests/ipython/test_ipython.py
+++ b/tests/ipython/test_ipython.py
@@ -38,7 +38,7 @@ def fake_metadata(tmp_path):
         project_name=PROJECT_NAME,
         kedro_init_version=PROJECT_INIT_VERSION,
         project_path=tmp_path,
-        add_ons=None,
+        tools=None,
     )
     return metadata
 
diff --git a/tests/tools/test_cli.py b/tests/tools/test_cli.py
index da01af4ee0..30ea89f625 100644
--- a/tests/tools/test_cli.py
+++ b/tests/tools/test_cli.py
@@ -101,7 +101,7 @@ def test_get_cli_structure_depth(self, mocker, fake_metadata):
                 "-v",
                 "--config",
                 "-c",
-                "--addons",
+                "--tools",
                 "-a",
                 "--example",
                 "-e",


Code review comments:
diff_hunk: @@ -170,13 +170,13 @@ def starter():
 @click.option("--starter", "-s", "starter_alias", help=STARTER_ARG_HELP)
 @click.option("--checkout", help=CHECKOUT_ARG_HELP)
 @click.option("--directory", help=DIRECTORY_ARG_HELP)
-@click.option("--addons", "-a", "selected_add_ons_flag", help=ADDON_ARG_HELP)
+@click.option("--tools", "-a", "selected_tools", help=TOOLS_ARG_HELP)
path: kedro/framework/cli/starters.py
text: @user2:
```suggestion
@user1.option("--tools", "-t", "selected_tools", help=TOOLS_ARG_HELP)
```

@author:
Good catch! I'll be going through those next