{"id":16640365,"url":"https://github.com/loreanvictor/tmplr","last_synced_at":"2025-03-15T12:30:30.243Z","repository":{"id":53836560,"uuid":"489470350","full_name":"loreanvictor/tmplr","owner":"loreanvictor","description":"Automate Code Scaffolding","archived":false,"fork":false,"pushed_at":"2024-09-07T18:01:19.000Z","size":2793,"stargazers_count":29,"open_issues_count":11,"forks_count":0,"subscribers_count":3,"default_branch":"main","last_synced_at":"2025-03-07T09:42:32.212Z","etag":null,"topics":["code","git","scaffold","starter","template"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/loreanvictor.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2022-05-06T19:24:14.000Z","updated_at":"2025-01-26T18:33:54.000Z","dependencies_parsed_at":"2023-11-26T07:29:03.164Z","dependency_job_id":"975fc656-bb28-4c80-a4ec-cced7d63c530","html_url":"https://github.com/loreanvictor/tmplr","commit_stats":{"total_commits":74,"total_committers":1,"mean_commits":74.0,"dds":0.0,"last_synced_commit":"12336ef3256918655fac2676b7b299c2cfbd4298"},"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/loreanvictor%2Ftmplr","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/loreanvictor%2Ftmplr/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/loreanvictor%2Ftmplr/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/loreanvictor%2Ftmplr/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/loreanvictor","download_url":"https://codeload.github.com/loreanvictor/tmplr/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":242961684,"owners_count":20213316,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["code","git","scaffold","starter","template"],"created_at":"2024-10-12T07:08:37.534Z","updated_at":"2025-03-15T12:30:29.588Z","avatar_url":"https://github.com/loreanvictor.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003cdiv align=\"right\"\u003e\n\n[![version](https://img.shields.io/npm/v/tmplr?label=\u0026color=black\u0026style=flat-square)](https://www.npmjs.com/package/tmplr)\n[![tests](https://img.shields.io/github/actions/workflow/status/loreanvictor/tmplr/test.yml?label=\u0026style=flat-square)](https://github.com/loreanvictor/tmplr/actions/workflows/test.yml)\n\n\u003c/div\u003e\n\n\u003c!--\n![Logo](./logo-dark.svg#gh-dark-mode-only)\n![Logo](./logo-light.svg#gh-light-mode-only)\n\n\u003cbr/\u003e\n--\u003e\n\n```\n       ┓\n ╋┏┳┓┏┓┃┏┓  repo\n ┗┛┗┗┣┛┗┛   templating 🚀\n     ┛\n```\n\nCreate projects from interactive templates, or enrich existing projects using interactive recipes.\n\n\u003cdiv align=\"center\"\u003e\n\n![Demo](./demo.svg)\n\n\u003c/div\u003e\n\nAny public repository can be a template for your next project. `tmplr` will download it (without git history) and execute its _templating recipe_, if one exists,\ninteractively filling up the project with contextual information.\n  \n```bash\nnpx tmplr owner/repo                  # 👉 get repo from github\nnpx tmplr gitlab:user/repo            # 🥽 or gitlab\nnpx tmplr git@bitbucket.org:user/repo # 🪣 or bitbucket\nnpx tmplr https://git.sr.ht/user/repo # 🛖 or source hut\nnpx tmplr local:/some/template        # 🏠 or local template\n```\n\n\u003cbr/\u003e\n\nRecipes set `tmplr` apart from other scaffolding tools:\n- 🌱 They can do simple tasks like removing a license file, updating README using git info, etc.\n- 🛸 They can do complex tasks such as adding new packages to a monorepo from a chosen preset.\n- 🧠 They can [use context](#contextual-values), such as git info or directory name, to fill the template.\n- 💬 They can [interactively](#expressions) ask for more info if needed.\n- 🧩 They can use other templates and [reusable recipes](#reusable-recipes).\n- ☂️ They are [powerful yet safe](#execution-safety) to run on your machine.\n- 🍰 They are [super easy](#recipe-syntax) to write and understand.\n\n\u003cbr/\u003e\n\n# Contents\n\n- [Installation](#installation)\n- [Usage](#usage)\n  - [Running Recipes](#running-recipes)\n  - [Reusable Recipes](#reusable-recipes)\n  - [Working Directory](#working-directory)\n  - [Execution Safety](#execution-safety)\n- [Making a Template](#making-a-template)\n  - [Template Recipes](#template-recipes)\n  - [Contextual Values](#contextual-values)\n  - [Recipe Syntax](#recipe-syntax)\n    - [Commands](#commands)\n    - [Expressions](#expressions)\n    - [Pipes](#pipes)\n- [Making a Reusable Recipe](#making-a-reusable-recipe)\n\n\u003cbr/\u003e\n\n# Installation\n\nInstall [Node.js](https://nodejs.org/en) and [npm](https://www.npmjs.com/package/npm), then run with [npx](https://www.npmjs.com/package/npx):\n```bash\nnpx tmplr owner/repo\n```\n\n\u003cbr/\u003e\n\n🍺 You _can_ install `tmplr` globally too:\n\n```bash\nnpm i -g tmplr\n```\n```bash\ntmplr owner/repo\n```\n\n\u003cbr\u003e\n\n👉 Use `@latest` tag to install/run the latest version:\n```bash\nnpx tmplr@latest owner/repo\n```\n```bash\nnpm i -g tmplr@latest\n```\nUse `version` command to check for updates:\n```bash\nnpx tmplr version\n```\n\n\u003cbr/\u003e\n\n# Usage\n\nGet public repositories from [GitHub](https://github.com):\n\n```bash\nnpx tmplr owner/repo\n```\n\nFor example, use [this template](https://github.com/vitrin-app/react-component-template) to create a publishable React component:\n\n```bash\nnpx tmplr vitrin-app/react-component-template\n```\n\n\u003cbr/\u003e\n\nGet public repositories from [GitLab](https://about.gitlab.com), [BitBucket](https://bitbucket.org) or [SourceHut](https://sourcehut.org):\n\n```bash\n# 🥽 download from GitLab\ntmplr gitlab:owner/repo\ntmplr git@gitlab.com:owner/repo\ntmplr https://gitlab.com/owner/repo\ntmplr gitlab:owner/group/repo --subgroup\n\n# 🪣 download from BitBucket\ntmplr bitbucket:owner/repo\ntmplr git@bitbucket.org:owner/repo\ntmplr https://bitbucket.org/owner/repo\n\n# 🛖 download from Sourcehut\ntmplr git.sr.ht/owner/repo\ntpmlr git@git.sr.ht:owner/repo\ntpmlr https://git.sr.ht/owner/repo\n\n# 🏠 use local template\ntmplr local:/path/to/template\n```\n\n\u003cbr/\u003e\n\nGet a tag, branch, commit or subdirectory:\n\n```bash\ntmplr owner/repo#branch       # 👉 branch\ntmplr owner/repo#tag          # 👉 release tag\ntmplr owner/repo#c0m1th45h    # 👉 commit hash\ntmplr owner/repo/subdirectory # 👉 sub directory\n```\n\n\u003cbr/\u003e\n\n\u003e 📖 Read more about command line options [here](cli.md).\n\n\u003cbr\u003e\n\n\u003e [!TIP]\n\u003e For cloning [gitlab subgroups](https://docs.gitlab.com/ee/user/group/subgroups/), use the `--subgroup` flag:\n\u003e ```bash\n\u003e tmplr gitlab:dude/fun-projects/starter-recipe --subgroup\n\u003e ```\n\n\u003cbr/\u003e\n\n## Running Recipes\n\nIf you have a repo with a recipe file locally and just want to run the recipe, \ngo to the project directory and run `tmplr` without arguments:\n\n```bash\nnpx tmplr\n```\n\n\u003cbr/\u003e\n\n\u003e [!TIP]\n\u003e A recipe is a `.tmplr.yml` file that modifies the project via interactive prompts / contextual info.\n\n\u003cbr\u003e\n\n## Reusable Recipes\n\nReusable recipes only change a part of your project, instead of determining its whole shape. For example, [this reusable recipe](https://github.com/trcps/license) helps you choose a license for your project. Use it like this:\n\n```bash\nnpx tmplr use trcps/license\n```\n\n\u003cbr\u003e\n\nWhile you can use only one template for your project, you can use multiple reusable recipes. For example, add a license, and then use [this recipe](https://github.com/trcps/npm-autopublish) to add a GitHub action for automatic publishing to NPM:\n\n```bash\nnpx tmplr use trcps/license\nnpx tmplr use trcps/npm-autopublish\n```\n\n\u003cbr\u003e\n\n\u003e [!TIP]\n\u003e `tmplr use` accepts same arguments for using a template:\n\u003e\n\u003e ```bash\n\u003e tmplr use owner/repo#mit       # 👉 get a branch\n\u003e tmplr use owner/repo#v1.0.0    # 👉 get a tag\n\u003e tmplr use bitbucket:owner/repo # 🪣 get from bitbucket\n\u003e tmplr use local:/path/to/repo  # 🏠 get from local\n\u003e ```\n\n\u003cbr\u003e\n\n\u003e 📖 Read more about the `use command` [here](cli.md#running-reusable-recipe).\n\n\u003cbr\u003e\n\n## Working Directory\n\nUse `--dir` (or `-d`) option to change the working directory (default is `.`):\n\n```bash\n# 👉 will clone owner/some-repo into my-new-project\ntmplr --dir my-new-project owner/some-repo\n```\n```bash\n# 👉 will run the recipe some-project/.tmplr.yml\ntmplr -d some-project\n```\n\n\u003cbr\u003e\n\n\u003e [!CAUTION]\n\u003e Recipes can change files only inside the working directory. By choosing their working directory, you basically choose which files they will have access to.\n\n\n\u003cbr/\u003e\n\n## Execution Safety\n\nGenerally, you should not run arbitrary scripts from untrusted sources on your machine. `tmplr` recipes are limited in what they can do, so that they can't do malicious acts, while remaining powerful enough for any scaffolding task.\n\n- The scope of recipes is limited to the working directory:\n  - Recipes can read, write, and remove files in their scope.\n  - Recipes can download contents of public repositories, from trusted sources (GitHub, GitLab, BitBucket \u0026 SourceHut), to their scope.\n- Recipes can read some contextual values.\n- Recipes can read environment variables.\n\n\u003cbr/\u003e\u003cbr/\u003e\n\n# Making a Template\n\nEvery public repository is a template. They can become more convenient to use by adding a recipe to interactively fill up the project using user's context. Simply add a `.tmplr.yml`, located at the root of your repo. People can use your template by running this:\n\n```bash\nnpx tmplr your/repo\n```\n\nUse `preview` to test how your repo would act as a template:\n\n```bash\nnpx tmplr preview\n```\n\n\u003e 📖 [Read this](cli.md#testing-recipes) to learn more about previewing templates.\n\n\u003cbr/\u003e\n\n## Template Recipes\n\nA recipe instructs `tmplr` on how to update project files with contextual info such as local git info, environment variables or directory name. A recipe can be a single command:\n\n```yaml\n# .tmplr.yml\nremove: LICENSE\n```\n\nOr multiple steps:\n\n```yaml\n# .tmplr.yml\nsteps:\n  - read: project_name\n    from: git.remote_name\n    fallback:\n      from: filesystem.rootdir\n  \n  - read: clone_url\n    from: git.remote_url\n  \n  - update: README.md\n```\n\n👆 When you _read_ a variable, it will be replaced in all the files copied / updated by the recipe. If `README.md` looks something like this:\n\n````md\n# {{ tmplr.project_name }}\n\nThis is my super awesome project. You can clone it using the following command:\n```bash\ngit clone {{ tmplr.clone_url }}\n```\n````\n\n\u003cbr\u003e\n\nAnd someone runs this recipe on their project, `https://github.com/john/my-project`, then `README.md` will become this:\n\n````md\n# my-project\n\nThis is my super awesome project. You can clone it using the following command:\n```bash\ngit clone https://github.com/john/my-project\n```\n````\n\n\u003cbr\u003e\n\n\u003e [!NOTE]\n\u003e After you read a variable such as `project_name`, in any file you update or copy, `{{ tmplr.project_name }}` will be replaced with the value read. If a variable is not resolved, then `tmplr` will leave it untouched.\n\n\u003e Make sure any template variable you use starts with `tmplr.` prefix. tmplr will ignore any variable that doesn't.\n\u003e \n\u003e ```yaml\n\u003e # ❌ this is wrong, and `{{ project_name }}` will remain untouched\n\u003e project:\n\u003e   name: {{ project_name }}\n\u003e ```\n\u003e ```yaml\n\u003e # ✅ this is correct. `{{ tmplr.project_name }}` will be replaced by the value read by the recipe.\n\u003e project:\n\u003e  name: {{ tmplr.project_name }}\n\u003e```\n\n\u003cbr\u003e\n\nWe have multiple _commands_ and _expressions_ used in the example recipe above:\n- [`steps`](#steps) is a command that runs multiple other commands sequentially,\n- [`read`](#read) is a command that reads a value into a variable,\n- [`update`](#update) is a command that updates a file using read variables,\n- [`from`](#from) is an expression, reading from [_contextual values_](#contextual-values) such as [`git.remote_url`](#git-context) or [`filesystem.rootdir`](#filesystem-context).\n\n\nRead more about the recipe syntax and available commands and expressions:\\\n📐 [More about recipe syntax](#recipe-syntax) \\\n🤖 [Available commands](#commands) \\\n🔌 [Available expressions](#expressions) \\\n🚰 [Available pipes](#pipes) \\\n🌡️ [Available contextual values](#contextual-values).\n\n\nIf you (like me) prefer learning by example, you can [check this example template repository](https://github.com/loreanvictor/tmplr-template-example), or check [these examples](./examples):\n\n- [Create GitHub template and run a recipe when someone uses your template](https://github.com/loreanvictor/tmplr/blob/main/examples/github-actions.md)\n- [Add new packages to monorepos using local templates](https://github.com/loreanvictor/tmplr/blob/main/examples/monorepo.md)\n\n\n\u003cbr/\u003e\n\n## Contextual Values\n\nRecipes can access following contexts:\n\n- [Git Context](#git-context)\n- [Filesystem Context](#filesystem-context)\n- [Environment Variables](#environment-variables)\n- [Date \u0026 Time](#date--time)\n- [Temporary Directories](#temporary-directories)\n- [Recipe Arguments](#recipe-arguments)\n\n\u003cbr/\u003e\n\n### Git Context\n\nValues related to git repository of the project. These only work inside a folder controlled by git.\n\n- `git.remote_url`: The origin URL of current git repository (this can be cloned, for example)\n- `git.remote_name`: The name of the origin (e.g. repository name)\n- `git.remote_provider`: The address of the git host (e.g. `https://github.com`)\n- `git.remote_owner`: The name of the user on the remote who owns the repository\n- `git.author_name`: The name of the person who made the first commit on the repo\n- `git.author_email`: Email address of the first committer.\n\nExample:\n\n```yaml\n# .tmplr.yml\nsteps:\n  - read: project_name\n    from: git.remote_name\n    fallback:\n      from: filesystem.rootdir\n\n  - read: author\n    from: git.author_name\n    fallback:\n      prompt: What is your name?\n\n  - read: repo_url\n    eval: 'https://{{ git.remote_provider }}/{{ git.remote_owner }}/{{ git.remote_name }}'\n\n  - update: package.json\n  - update: README.md\n\n  # ...\n```\n\n\n\u003cbr\u003e\n\n\u003e [!WARNING]\n\u003e \n\u003e If the recipe is run outside of a repository (where there is no `.git`), then git contextual values won't be available. Read git value using [`from`](#from), and provide a fallback.\n\n\u003e [!WARNING]\n\u003e\n\u003e Even inside a git repository, if there are 0 commits, then `git.author_name` and `git.author_email` will be empty strings.\n\n\u003cbr/\u003e\n\n### Filesystem Context\n\n- `filesystem.root`: Absolute address of the root directory (which the recipe is being executed in)\n- `filesystem.rootdir`: The name of the root directory\n- `filesystem.scope`: Absolute address of the scope of this recipe.\n- `filesystem.scopedir`: The name of the scope directory.\n\nThe root directory, `filesystem.root`, is where the recipe file is located. This is also the addrerss which all\nrelative addresses in the recipe are interpreted relative to. The scope of the recipe, `filesystem.scope`, is where the recipe can access (read/write). The scope can be differnt from the root: when a recipe is called by another recipe (via [run](#run) or [use](#use) commands), the called recipe has the same\nscope to the caller recipe, though their roots might differ.\n\nExample:\n\n```yaml\n# .tmplr.yml\nsteps:\n  # ...\n\n  # 👇 will apply a reusable recipe to add proper license for the project.\n  #    check the docs for the `use` command for more info.\n  - use: trcps/license\n    with:\n      owner: '{{ git.author_name }}'\n      project_name: '{{ filesystem.scopedir }}'\n      project_url: '{{ git.remote_url }}'\n\n  # ...\n```\n\n\u003cbr/\u003e\n\n### Environment Variables\n\nUse `env.some_var` to access some environment variable. If it is not defined, an empty string will be returned.\n\n\u003cbr/\u003e\n\n### Date \u0026 Time\n\n- `datetime.now`: The current date and time in [ISO format](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toISOString) (e.g. `2023-07-26T14:06:38.794Z`)\n- `datetime.date`: The current date (e.g. `7/26/2023`).\n- `datetime.time`: The current time in the local timezone (e.g. `5:15 PM`).\n- `datetime.year`: The current year (e.g. `2023`).\n- `datetime.month`: The current month (e.g. `6`).\n- `datettime.month_of_year`: The name of the current month (e.g. `July`).\n- `datetime.day`: The current day (e.g. `26`).\n- `datetime.day_of_week`: The name of the current day (e.g. `Wednesday`).\n- `datetime.hour`: The current hour in the local timezone (e.g. `17`).\n- `datetime.minute`: The current minute in the local timezone (e.g. `15`).\n- `datetime.second`: The current time seconds (e.g. `38`).\n- `datetime.millisecond`: The current time milliseconds (e.g. `794`).\n\n\u003cbr/\u003e\n\n\u003e [!TIP]\n\u003e Use [date \u0026 time pipes](#date--time-pipes) to further format date and time strings.\n\n\u003cbr/\u003e\n\n### Temporary Directories\n\nUse `tmpdir.some_name` to automatically create temporary directories.\n\n```yml\nsteps:\n  #\n  # some initial steps \n  #\n  \n  - copy: some_file.go\n    to: '{{ tmpdir.go_file }}/some_file.go'\n      \n  #\n  # some other steps\n  #\n  \n  - copy: '{{ tmpdir.go_file }}/some_file.go'\n    to: some_other_file.go\n```\n\nTemporary directories will be deleted after the recipe has finished executing.\n\n\u003cbr/\u003e\n\n### Recipe Arguments\n\nRecipes can also [run](#run) other local recipes or [use](#use) publicly published recipes. The caller recipe can pass arguments\nto the called recipe, which will be available on `args` context.\n\n```yml\n# called.yml\nsteps:\n  - read: remote_url\n    from: git.remote_url\n    \n  - update:\n      path: '{{ args.readme }}'\n```\n```yml\n# .tmplr.yml\nsteps:\n  - run: ./called.yml\n    with:\n      - readme:\n          path: ./README.md\n```\n\n\u003cbr/\u003e\n\n\u003e [!TIP]\n\u003e Recipe arguments are evaluated lazily. If a prompt is passed as an argument, the user will be prompted the first time the argument is accessed, not when the recipe is called.\n\n\u003cbr/\u003e\n\n## Recipe Syntax\n\nRecipes are composed of [_commands_](#commands) and [_expressions_](#expressions). _Commands_ instruct actions (i.e. read a value, update a file, etc), and _expressions_ calculate string values used by commands. A recipe descirbes a single command, which can itself be composed of multiple other steps:\n\n\u003cbr/\u003e\n\n```yaml\n# .tmplr.yml\nremove: LICENSE\n```\n☝️ Here the recipe is a single _remove_ command.\n\n\u003cbr/\u003e\n\n```yaml\n# .tmplr.yml\nsteps:\n  - read: project_name\n    from: git.remote_name\n    fallback:\n      prompt: What is the name of the project?\n      default:\n        from: filesystem.rootdir\n  \n  - update: README.md\n```\n\n☝️ Here the recipe is a single _steps_ command, which is composed of multiple steps (commands). Take a closer look at the initial _read_ command:\n\n```yml\n  - read: project_name\n    from: git.remote_name\n    fallback:\n      prompt: What is the name of the project?\n      default:\n        from: filesystem.rootdir\n```\n\nThis command [read](#read)s a variable, `project_name`, [_from_](#from) a contextual value. From this point on, you can use this variable in other expressions, pass it to other recipes you call, and when you [copy](#copy) or [update](#update) a file, `{{ tmplr.project_name }}` will be replaced with the variable's value. If the contextual value can't be resolved, it will fallback to a [_prompt_](#prompt), asking the user for the value, suggesting the name of the current directory as the default value.\n\nHere you can see the corresponding syntax tree of this example recipe:\n```\nSteps Command\n  ┃\n  ┣━━ Read Command\n  ┃     ┃\t\n  ┃     ┗━━ From Expression\n  ┃          ┃\t\n  ┃          ┗━(fallback)━ Prompt Expression\n  ┃               ┃\t\n  ┃               ┗━(default)━ From Expression\n  ┃\n  ┗━ Update Command\n       ┃\n       ┗━ Value Expression\n```\n\nThe string passed to the [update](#update) command, `README.md`, is also an expression, which means it could be replaced\nby a _prompt_:\n\n```yml\n  - update:\n      prompt: Which file do you want to update?\n      default: README.md\n```\n\nOr can reference variables / contextual values:\n\n```yml\n  - update: '{{ readme_file }}.md'\n```\n```yml\n  - update: '{{ env.README_FILE }}.md'\n```\n\n\u003cbr\u003e\n\n\u003e [!TIP]\n\u003e\n\u003e For using variables in expressions (i.e. inside recipe files), you don't need the `tmplr.` prefix. You can also directly access\n\u003e contextual values such as `git.remote_owner`, `filesystem.rootdir`, or `tmpdir.some_dir` directly. You can also use [pipes](#pipes) to transform values.\n\u003e\n\u003e **Note** that inside files that are [copied](#copy) or [updated](#update), you DO NEED the `tmplr.` prefix, and you don't have access to other\n\u003e contextual values. If you need to use these values within these files, [read](#read) them into a variable first.\n\n\u003cbr/\u003e\n\n### Commands\n\n- [**read**](#read): reads a value into a variable, so that the variable can be used to update subsequent files.\n- [**update**](#update): updates contents of some files, using variables read.\n- [**copy**](#copy): copies some files, also updating them using variables read.\n- [**write**](#write): writes given content to a file.\n- [**remove**](#remove): removes some files.\n- [**steps**](#steps): runs a bunch of commands in a step by step manner.\n- [**if**](#if): runs a command conditionally.\n- [**skip**](#skip): skips current steps or recipe.\n- [**degit**](#degit): copies content of given repository to given folder.\n- [**run**](#run): runs another local recipe file, with given arguments.\n- [**use**](#use): runs a remote recipe file, with given arugments.\n\n\n\u003cbr/\u003e\n\n#### Read\n\n\u003e _Command_\n\u003e \n\u003e ```yml\n\u003e read: \u003cvariable name\u003e\n\u003e \u003cexpression\u003e\n\u003e ```\n\nReads some value into a variable. The variable can then be used in subsequent expressions or passed as an argument to other called recipes. It will also be replaced in all files that are [updated](#update) or [copied](#copy).\n\n```yml\nsteps:\n  - read: project_name\n    from: filesystem.rootdir\n```\n\n☝️ After executing this command, if you [update](#update) or [copy](#copy) any file that contains `{{ tmplr.project_name }}`, the value of the variable will be replaced.\n\n\u003cbr/\u003e\n\n#### Update\n\u003e _Command_\n\u003e ```yml\n\u003e update:\n\u003e   \u003cexpression\u003e\n\u003e include hidden?: \u003cboolean\u003e\n\u003e ```\n\nUpdates a file, using variables that are already [`read`](#read).\n\n```yml\nsteps:\n  - read: name\n    prompt: What is your name?\n  \n  - update: README.md\n```\n```yml\nsteps:\n  - read: docs_folder\n    prompt: Where do you keep the docs?\n    choices:\n      - docs\n      - documents\n      - other:\n          prompt: Specify the folder name ...\n  - update:\n      path: '{{ docs_folder }}/Home.md'\n```\n\n👉 Pass an [extended glob pattern](https://www.npmjs.com/package/minimatch) to update multiple files at once:\n```yml\nupdate: 'src/**/*.java'\n```\n\nWhen using a glob pattern, hidden files (starting with a dot, e.g. `.gitignore`) and files in hidden folders (e.g. `.github/workflows/publish.yml`) are ignored. Update hidden files by explicitly mentioning them:\n```yml\n- update: '**/.*.java'\n- update: '**/.**/**/*.java'\n```\nOr by using the `include hidden` option:\n```yml\nupdate: '**/*'\ninclude hidden: true\n```\n\n\u003cbr/\u003e\n\n#### Copy\n\u003e _Command_\n\u003e ```yml\n\u003e copy:\n\u003e   \u003cexpression\u003e\n\u003e to:\n\u003e   \u003cexpression\u003e\n\u003e include hidden?: \u003cboolean\u003e\n\u003e```\n\nCopies a file, creating necessary folders, replacing existing files. Will also [update](#update) the copied file, replacing all [read](#read) variables with their values.\n\n```yml\nsteps:\n  - read: email\n    from: git.author_email\n  \n  - copy: .template/CODE_OF_CONDUCT\n    to: CODE_OF_CONDUCT\n```\n```yml\nsteps:\n  - read: email\n    from: git.author_email\n  \n  - degit: some/license_template\n    to:\n      path: '{{ tmpdir.license }}'\n  \n  - copy:\n      path: '{{ tmpdir.license }}/LICENSE'\n    to: LICENSE\n```\n👉 Pass an [extended glob pattern](https://www.npmjs.com/package/minimatch) to copy multiple files at once. When\ncopying multiple files, the `to` expression is treated as a folder address:\n```yml\ncopy: ./template/code/**/*.java\nto: src/main/java\n```\n☝️ The structure of the copied files will be preserved in the destination folder. In the above example,\n`./template/code/com/example/Hello.java` will be copied to `src/main/java/com/example/Hello.java`.\n\n\u003cbr\u003e\n\nWhen using a glob pattern, hidden files (starting with a dot, e.g. `.gitignore`) and files in hidden folders (e.g. `.github/workflows/publish.yml`) are ignored by default. Copy hidden files by explicitly mentioning them:\n```yml\n- copy: '**/.*.java'\n  to: src/main/java\n\n- copy: '**/.**/**/*.java'\n  to: src/main/java\n```\nOr by using the `include hidden` option:\n```yml\ncopy: '**/*.java'\nto: src/main/java\ninclude hidden: true\n```\n\n\u003cbr/\u003e\n\n#### Write\n\u003e _Command_\n\u003e ```yml\n\u003e write:\n\u003e   \u003cexpression\u003e\n\u003e to:\n\u003e   \u003cexpression\u003e\n\u003e```\n\nWrites given content to a file, creating necessary folders, replacing existing files. Will replace all [read](#read) variables with their values inside the written content (not the whole file).\n\n```yml\nsteps:\n  - read: badge_content\n    from file: .template/badge.md\n\n  - read: readme_content\n    from file: README.md\n\n  - write: '{{ badge_content }}\\n{{ readme_content }}'\n    to: README.md\n```\n\n\u003cbr/\u003e\n\n#### Remove\n\u003e _Command_\n\u003e ```yml\n\u003e remove:\n\u003e   \u003cexpression\u003e\n\u003e include hidden?: \u003cboolean\u003e\n\u003e ```\nRemoves a file or a folder.\n```yml\nsteps:\n  # do some other stuff\n  \n  - remove: .tmplr.yml\n```\n👉 Pass an [extended glob pattern](https://www.npmjs.com/package/minimatch) to remove multiple files at once:\n```yml\nremove: ./**/*.tmplr.*\n```\n\nWhen using a glob pattern, hidden files (starting with a dot, e.g. `.gitignore`) and files in hidden folders (e.g. `.github/workflows/publish.yml`) are ignored by default. Remove hidden files by explicitly mentioning them:\n\n```yml\n- remove: '**/.*'\n- remove: '**/.**/**/*'\n```\n\nOr by using the `include hidden` option:\n\n```yml\nremove: '**/*'\ninclude hidden: true\n```\n\nNote that when passing a glob pattern, folders are not removed. If you want to remove a folder, you need to pass the folder path explicitly:\n\n```yml\nremove: .github\n```\n\n\u003cbr/\u003e\n\n#### Steps\n\u003e _Command_\n\u003e ```yml\n\u003e steps:\n\u003e   - \u003ccommand\u003e\n\u003e   - \u003ccommand\u003e\n\u003e   - ...\n\u003e ```\n\nRuns given commands step by step.\n```yml\nsteps:\n  - read: name\n    from: git.author_name\n    fallback:\n      from: env.USER\n  \n  - update: package.json\n  - copy: .template/README.md\n    to: README.md\n  - remove: .template\n```\n  \n\u003cbr/\u003e\n\n#### If\n\u003e _Command_\n\u003e ```yml\n\u003e if: \u003cvariable / contextual value\u003e\n\u003e \u003ccommand\u003e\n\u003e else?:\n\u003e   \u003ccommand\u003e\n\u003e ```\n\u003e ```yml\n\u003e if:\n\u003e   \u003cexpression\u003e\n\u003e \u003ccommand\u003e\n\u003e else?:\n\u003e   \u003ccommand\u003e\n\u003e ```\n\u003e ```yml\n\u003e if not: \u003cvariable / contextual value\u003e\n\u003e \u003ccommand\u003e\n\u003e else?:\n\u003e   \u003ccommand\u003e\n\u003e ```\n\u003e ```yml\n\u003e if not:\n\u003e   \u003cexpression\u003e\n\u003e \u003ccommand\u003e\n\u003e else?:\n\u003e   \u003ccommand\u003e\n\u003e ```\nRuns given command if given variable, contextual value, or expression resolves to a non-empty string. Runs the _else_ command if the condition fails.\n```yml\nsteps:\n  - if: git.remote_url\n    copy: README.git-template.md\n    to: README.md\n    else:\n      copy: README.non-git-template.md\n      to: README.md\n```\n\n\u003cbr/\u003e\n\nCan also be used as a ternary operator:\n```yml\nprompt: Wassup?\ndefault:\n  if: some_var\n  eval: 'Hello {{ some_var }}!'\n  else:\n    eval: 'Hello world!'\n```\n\n\u003cbr/\u003e\n\n#### Skip\n\n\u003e _Command_\n\u003e ```yml\n\u003e skip: steps\n\u003e ```\n\u003e ```yml\n\u003e skip: recipe\n\u003e ```\n\nSkips the rest of current [steps](#steps) or recipe. Useful for conditional execution:\n```yml\nsteps:\n  # ...\n\n  - prompt: Are you sure?\n    choices:\n      - Yes\n      - No:\n          skip: recipe\n\n  # ...\n```\n\n\u003cbr/\u003e\n\n#### Degit\n\n\u003e _Command_\n\u003e ```yml\n\u003e degit:\n\u003e   \u003cexpression\u003e\n\u003e to?:\n\u003e   \u003cexpression\u003e\n\u003e subgroup?: \u003cboolean\u003e\n\u003e ```\nCopies contents of given repository into specified folder (using [degit](https://github.com/Rich-Harris/degit)). If destination is not specified, will copy into the same folder as the running recipe. Accepts the same sources as `tmplr` command.\n```yml\nsteps:\n  - degit: user/repo\n    to:\n      eval: '{{ tmpdir.repo }}'\n```\n\u003cbr/\u003e\n\n\u003e [!TIP]\n\u003e For cloning [gitlab subgroups](https://docs.gitlab.com/ee/user/group/subgroups/), use the `subgroup` option.\n\n\u003cbr/\u003e\n\n#### Run\n\u003e _Command_\n\u003e ```yml\n\u003e run:\n\u003e   \u003cexpression\u003e\n\u003e with?:\n\u003e   \u003cargname\u003e:\n\u003e     \u003cexpression\u003e\n\u003e   \u003cargname\u003e:\n\u003e     \u003cexpression\u003e\n\u003e   ...\n\u003e read?:\n\u003e   \u003cvarname\u003e: \u003coutname\u003e\n\u003e   \u003cvarname\u003e: \u003coutname\u003e\n\u003e   ...\n\u003e ```\nParses and executes given local recipe. You can pass arguments to the recipe file (which can be accessed via the [`args` context](#recipe-arguments) lazily). The recipe WILL NOT have access to variables you have [read](#read) by default. You can read the variables [read](#read) by the recipe into variables in your own recipe.\n\n```yml\nsteps:\n  - read: name\n    from: git.author_name\n\n  - run: .templates/util/some-recipe.yml\n    with:\n      name: name             # will pass `name` variable\n      remote_url:\n        from: git.remote_url # this will be executed lazily\n        fallback:\n          prompt: What is the remote URL?\n    read:\n      lockfile: lockfile     # will read `lockfile` variable of the inner recipe into `lockfile` variable of outer recipe\n      some_success: success  # will read `success` variable of the inner recipe into `some_success` variable of outer recipe\n```\n\n\u003cbr/\u003e\n\n\u003e [!IMPORTANT]\n\u003e Relative paths are resolved _relative to the recipe_. In the example above, the caller recipe referencing `README.md` will access `README.md` at the root of the project, while the called recipe accessing `README.md` would access `.templates/util/README.md`. It is recommended to use the [path](#path) expression to turn all path strings into absolute paths.\n\n\u003cbr\u003e\n\n\u003e 🤡 **USELESS FACTOID**\n\u003e\n\u003e When running `tmplr owner/repo`, tmplr basically runs the following recipe:\n\u003e ```yml\n\u003e steps:\n\u003e   - degit: owner/repo\n\u003e     to: .\n\u003e   - run: .tmplr.yml\n\u003e ```\n\n\u003cbr/\u003e\n\n#### Use\n\u003e _Command_\n\u003e ```yml\n\u003e use:\n\u003e   \u003cexpression\u003e\n\u003e with?:\n\u003e   \u003cargname\u003e:\n\u003e     \u003cexpression\u003e\n\u003e   \u003cargname\u003e:\n\u003e     \u003cexpression\u003e\n\u003e   ...\n\u003e read?:\n\u003e   \u003cvarname\u003e: \u003coutname\u003e\n\u003e   \u003cvarname\u003e: \u003coutname\u003e\n\u003e   ...\n\u003e ```\n\nRuns given [reusable recipe](#reusable-recipes). For example, the following will help users add a licence to their project:\n\n```yml\nsteps:\n  # ...\n\n  - use: trcps/license\n    with:\n      owner: '{{ git.author_name }}'\n      project_name: '{{ filesystem.scopedir }}'\n      project_url: '{{ git.remote_url }}'\n\n  # ...\n```\n\n`use` downloads, parses and executes given recipe from a public repository. It fetches the specified repository (using [degit](#degit)) into a temporary directory at the root of the project, locates `.tmplr.yml` in that directory and [runs](#run) it, and removes the directory. The specified repository MUST have a `.tmplr.yml` file at its root.\n\n```yml\nsteps:\n  - read: name\n    from: git.author_name\n\n  - use: some-user/some-repo\n    with:\n      name: name               # will pass `name` variable\n      remote_url:\n        from: git.remote_url   # this will be executed lazily\n        fallback:\n          prompt: What is the remote URL?\n    read:\n      lockfile: lockfile       # will read `lockfile` variable of the inner recipe into `lockfile` variable of outer recipe\n      some_success: success    # will read `success` variable of the inner recipe into `some_success` variable of outer recipe\n```\n\n\u003cbr\u003e\n\n\u003e 💡 Read [this section](#making-a-reusable-recipe) to learn more about creating reusable recipes.\n\n\u003cbr/\u003e\n\n### Expressions\n\n- [**from**](#from): reads from a contextual value.\n- [**prompt**](#prompt): asks the value from user.\n- [**choices**](#choices): asks the value from user, but gives them some predetermined choices.\n- [**eval**](#eval): evaluates an expression.\n- [**path**](#path): evaluates to an absolute path value.\n- [**exists**](#exists): checks if a file exists or not.\n- [**from file**](#from-file): reads content of a file.\n\n\u003cbr/\u003e\n\n#### From\n\u003e _Expression_\n\u003e ```yml\n\u003e from: \u003ccontextual-variable\u003e\n\u003e fallback?:\n\u003e   \u003cexpression\u003e\n\u003e ```\nResolves given contextual value. If it can't be resolved,\nwill evaluate the fallback expression, or an empty string if no fallback is specified.\n```yml\nsteps:\n  - read: username\n    from: git.remote_owner\n    fallback:\n      from: env.USER\n```\n\n\u003cbr/\u003e\n\n#### Prompt\n\u003e _Expression_\n\u003e ```yml\n\u003e prompt: \u003cmessage\u003e\n\u003e default?:\n\u003e   \u003cexpression\u003e\n\u003e```\nAsks the user for a value. If a default value is provided, then that will be suggested to the user\nas well.\n```yml\nsteps:\n  - read: username\n    prompt: What is your username?\n    default:\n      from: git.author_name\n      fallback:\n        from: env.USER\n```\n\n\u003cbr/\u003e\n\n#### Choices\n\u003e _Expression_\n\u003e ```yml\n\u003e prompt: \u003cmessage\u003e\n\u003e choices:\n\u003e   - \u003clabel\u003e:\n\u003e       \u003cexpression\u003e\n\u003e   - \u003clabel\u003e:\n\u003e       \u003cexpression\u003e\n\u003e   ...\n\u003e ```\nAsks the user to choose from a list of values. Evaluates the corresponding expression of each choice _after_ the user\nhas selected it (so you can chain prompts and other expressions safely).\n```yml\nsteps:\n  - read: username\n    prompt: What is your username?\n    choices:\n      - Read it from git:\n          from: git.author_name\n      - Read it from env:\n          from: env.USER\n      - John Doe # 👉 here the value is the same as the label.\n      - None:\n          prompt: Ok but what is your username though?\n```\n\n\u003cbr/\u003e\n\n#### Eval\n\u003e _Expression_\n\u003e ```yml\n\u003e eval: \u003cexpression\u003e\n\u003e steps?:\n\u003e   - \u003ccommand\u003e\n\u003e   - \u003ccommand\u003e\n\u003e   ...\n\u003e ```\n\nEvaluates given expression, similar to evaluation of template variables in [updated](#update) or [copied](#copy)\nfiles, except you don't need the `tmplr.` prefix, and can access [contextual values](#contextual-values) too.\n\n```yml\nsteps:  \n  read: git_url\n  from: git.remote_url\n  fallback:\n    eval: 'https://github.com/{{ env.USER | snake_case }}/{{ filesystem.rootdir }}.git'\n```\n\nYou can optionally pass a list of commands as the _steps_ property. These are usually (but not necessarily) some [read](#read)s\nto fetch further values required for the evaluation. Note that these commands only get executed if the _Eval Expression_\nitself is evaluated.\n\n```yml\nsteps:\n  - read: git_url\n    from: git.remote_url\n    fallback:\n      steps:\n        - read: git_provider\n          prompt: Where is the project hosted?\n          choices:\n            - GitHub: 'https://github.com'\n            - BitBucket: 'https://bitbucket.org'\n            - Source Hut: 'https://git.sr.ht'\n            - Other:\n                prompt: Please specify ...\n        - read: git_owner\n          from: env.USER\n          fallback:\n            prompt: What is your username?\n      eval: '{{ git_provider }}/{{ git_owner }}/{{ filesystem.rootdir }}.git'  \n```\n\n\u003cbr/\u003e\n\n#### Path\n\u003e _Expression_\n\u003e ```yml\n\u003e path: \u003cexpression\u003e\n\u003e ```\nSimilar to [**eval**](#eval) but for strings representing file paths. If the expression evaluates to a relative path, will\nturn it into an absolute path (relative paths are _relative to the recipe_). Use it to pass path\narguments to and reading path values from recipes you [use](#use) or [run](#run).\n```yml\nsteps:\n  # ...\n  - degit: some/repo\n    to:\n      eval: '{{ tmpdir.some_repo }}'\n\n  - use: some/recipe\n    with:\n      readme:\n        path: '{{ tmpdir.some_repo }}/README.md'\n```\n\n\u003cbr\u003e\n\n#### Exists\n\u003e _Expression_\n\u003e ```yml\n\u003e exists:\n\u003e   \u003cexpression\u003e\n\u003e include hidden?: \u003cboolean\u003e\n\u003e ```\n\nChecks if a file exists or not. Can be passed a glob pattern, in which case checks if any file matching given pattern exists or not. If it does, returns the path of the first matching file.\n\n```yml\nsteps:\n  - if:\n      exists: '**/*'\n    prompt: 'Directory is not empty. Overwrite?'\n    choices:\n      - Yes\n      - No:\n          skip: recipe\n  \n  # ...\n```\n\nSimilar to [copy](#copy), [update](#update) and [remove](#remove), the command will by default ommit hidden files unless explicitly mentioned in the glob pattern. Override this using `include hidden` property:\n\n```yml\nexists: '**/*'\ninclude hidden: true\n```\n\n\u003e [!IMPORTANT]\n\u003e `exists` only checks for existence of files, and ignores directories. So this is wrong:\n\u003e ```yaml\n\u003e # ❌ WRONG\n\u003e exists: 'my-dir/'\n\u003e ```\n\u003e Use `**/*` glob pattern instead:\n\u003e ```yaml\n\u003e # ✅ CORRECT\n\u003e exists: 'my-dir/**/*'\n\u003e ```\n\n\n\n\n\n\n\u003cbr\u003e\n\n#### From File\n\u003e _Expression_\n\u003e ```yml\n\u003e from file: \u003cexpression\u003e\n\u003e ```\n\nReads the content of a file.\n\n```yml\nsteps:\n  - read: readme\n    from file: README.md\n```\n\n\u003cbr\u003e\n\n### Pipes\n\n- [**Letter Case Pipes**](#letter-case-pipes)\n- [**String Pipes**](#string-pipes)\n- [**Date \u0026 Time Pipes**](#date--time-pipes)\n- [**Regexp Matching**](#regexp-matching)\n\n\u003cbr\u003e\n\nUse pipes to modify variables, either in [copied](#copy) / [updated](#update) files, or in the recipe itself:\n\n```yaml\n# .tmplr.yml\nsteps:\n  - read: name\n    prompt: whats the name?\n  \n  - copy: .templates/template.md\n    to: '{{ name | path/case }}.md'\n\n  - remove: .templates\n```\n\n````markdown\n\u003c!-- .templates/template.md --\u003e\n\n# {{ tmplr.name | Capital Case }}\n\nThis is a super awesome project that can be installed by running:\n```bash\nnpm i {{ tmplr.name | kebab-case }}\n```\n````\n☝️ Running this recipe with the name `cool project` will result in `cool/project.md` with the following contents:\n````markdown\n# Cool Project\n\nThis is a super awesome project that can be installed by running:\n```bash\nnpm i cool-project\n```\n````\n\n\u003cbr\u003e\n\n#### Letter Case Pipes\n\nUse the following pipes to change the casing of a string (they are case-sensitive):\n\n```\n- camelCase           - Capital Case       - CONSTANT_CASE \n- dot.case            - Header-Case        - kebab-case\n- PascalCase          - path/case          - param-case\n- Sentence case       - UPPERCASE          - lowercase\n```\n\n\u003cbr\u003e\n  \n#### String Pipes\n\nUse `skip` and `trim` pipes to remove the given number of characters from the beginning and\nthe end of the string, respectively:\n\n```yml\nsteps:\n  - read: component_name\n    prompt: What is the name of the component?\n    default:\n      #\n      # if the directory name is 'react-my-component', then\n      # this will evaluate to 'MyComponent'.\n      #\n      eval: '{{ filesystem.rootdir | skip: 6 | PascalCase }}'\n```\n\n👉 Pass string values to `trim` and `skip` to remove the given string\nfrom the start / end of the variable. Only works if the variable starts / ends with exactly the given string:\n\n```yml\nsteps:\n  - read: component_name\n    prompt: What is the name of the component?\n    default:\n      #\n      # if the directory name is 'react-my-component', then\n      # this will evaluate to 'MyComponent'. However, if the\n      # directory name does not start with 'react-', then it will\n      # not modify it.\n      #\n      eval: '{{ filesystem.rootdir | skip: react- | PascalCase }}'\n```\n\n\u003cbr\u003e\n\n#### Date \u0026 Time Pipes\n\nUse `date format` to format a value representing some date:\n\n```yml\nsteps:\n  - read: date\n    eval: '{{ datetime.now | date format: YYYY-MM-DD }}'\n\n  - update: LICENSE\n```\n\nUse `time format` to format a time string:\n\n```yml\nsteps:\n  - read: time\n    eval: '{{ datetime.now | time format: HH:mm:ss }}'\n```\n\nUse `datetime format` to format both:\n\n```yml\nread: now\neval: '{{ datetime.now | datetime format: YYYY-MM-DD HH:mm:ss }}'\n```\n\n\u003cbr\u003e\n\n\u003e 💡 [Read this](https://github.com/knowledgecode/date-and-time#formatdateobj-arg-utc) to learn more about possible formats.\n\n\u003cbr\u003e\n\n👉 To format date / time using locale specific formats, pass `locale \u003clocale\u003e` to any of the pipes:\n\n```yml\nread: now\neval: '{{ datetime.now | datetime format: locale en-US }}'\n```\n```yml\nread: zeit\neval: '{{ datetime.now | time format: locale de }}'\n```\n\n\u003cbr\u003e\n\n\u003e 💡 Language and locale codes are based on [this](https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes) and [this](https://en.wikipedia.org/wiki/List_of_ISO_3166_country_codes) standards. You can use tools like [this](https://www.science.co.il/language/Locale-codes.php) to figure out which tags you should use.\n\n\u003cbr\u003e\n\n#### Regexp Matching\n\nUse `matches` pipe to check if a variable matches given string/pattern. This pipe returns the given string if it matches, and returns an empty string otherwise. Use this for [conditional commands](#if):\n\n```yml\nsteps:\n  # ...\n\n  - if:\n      eval: '{{ some_var | matches: some value }}'\n    update: some_file.txt\n    else:\n      update: some_other_file.txt\n\n  # ...\n```\n```yml\nif:\n  eval: '{{ database | matches: /Mongo/ }}'\ncopy: mongodb.config.js\nto: ./src/config/db.config.js\nelse:\n  copy: postgres.config.js\n  to: ./src/config/db.config.js\n```\n\n\u003cbr\u003e\n\n# Making a Reusable Recipe\n\nA reusable recipe is similar to a template, except that it should change only a specific part of a project. They might be applied directly, or used as part of another recipe.\n\nFor example, [this reusable recipe](https://github.com/trcps/npm-autopublish) adds a GitHub action to automatically publish to NPM on a version bump. It can be directly applied to a project like this:\n\n```bash\ntmplr use trcps/npm-autopublish\n```\n\nOr it can be used as part of another recipe:\n\n```yaml\nsteps:\n  # ...\n\n  - use: trcps/npm-autopublish\n\n  # ...\n```\n\n\u003cbr\u003e\n\nMaking a reusable recipe is similar to making a template repository, with following differences:\n\n- Your repository will be cloned to a temporary directory, not the root of the project.\n- This temporary directory will be removed when your recipe is finished running.\n\n👉 Copy any files you want to add to the project explicitly:\n\n```yaml\n# inside some reusable recipe ...\nsteps:\n  - copy: workflow.yml\n    to: ../.github/workflows/publish.yml\n```\n\n\u003cbr\u003e\n\n👉 Read or write files from the host project using `../file`. OR, use [filesystem scope](#filesystem-context) and [path](#path):\n\n```yaml\nsteps:\n  - copy: workflow.yml\n    to: \n      path: '{{ filesystem.scope }}/.github/workflows/publish.yml'\n```\n\n\u003cbr\u003e\n\n👉 Use `tmplr preview:use` to see what would happen if your repo was used as a reusable recipe:\n\n```bash\ntmplr preview:use\n```\n\nThis command applies your recipe to an empty `.tmplr-preview` directory, where you can inspect the results.\n\n\u003cbr\u003e\u003cbr\u003e\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Floreanvictor%2Ftmplr","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Floreanvictor%2Ftmplr","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Floreanvictor%2Ftmplr/lists"}