Skip to content

Bootstrap a Taskfile project

This guide explains how init-project and update-project set up and maintain a project, how the AGENTS.md and .gitignore templates are structured, and what survives an update.

Initialize a project

Run init-project in an empty directory:

task init-project

Or use the short alias:

task inp

The command runs git init and creates the missing files. Existing files are never overwritten.

File Source
tmp/ Created as directory.
.gitignore Rendered from .gitignore.template.
task Rendered from task.template.
.env.template Copied from the repository root.
AGENTS.md Rendered from templates/AGENTS.md.
CHANGELOG.md Copied from templates/CHANGELOG.md.
README.md Created empty.
LICENSE Copied from the selected templates/LICENSE.*.

Created files are reported at the end:

Created: tmp/ .gitignore task .env.template AGENTS.md CHANGELOG.md README.md LICENSE

Interactive selection

When fzf is installed, init-project asks which parts to include:

  • Select task parts - the command groups in task (Task, Files, Git, SOPS, ...).
  • Select gitignore options - the optional blocks in .gitignore.
  • Select AGENTS.md tooling options - the sections under ## Environment & tooling.
  • Select AGENTS.md coding conventions - the sections under ## Coding conventions.
  • Select license - LICENSE.AGPL-3.0 or LICENSE.MIT.

Use Tab to multi-select and Enter to confirm. Without fzf, or when the command runs without a terminal, the full template is copied and the default license is used.

Licenses

Two license templates are available:

Template License
templates/LICENSE.AGPL-3.0 GNU Affero General Public License v3. Default.
templates/LICENSE.MIT MIT License.

Replace the <year> and <copyright holders> placeholders in the MIT license after creation.

Update a project

Run update-project to refresh a project from the templates:

task update-project

Or use the short alias:

task up

The command accepts a path and two optional flags:

task update-project [--agents] [--gitignore] [path]
Argument Effect
path Target directory. Defaults to the current directory.
--agents Also update AGENTS.md.
--gitignore Also update .gitignore.

Without flags only task is updated.

Missing files are created instead of causing an error. update-project creates task, AGENTS.md, CHANGELOG.md and LICENSE when they are absent, and reports each one:

Created files: task AGENTS.md CHANGELOG.md LICENSE

Existing files are merged, never replaced. This makes the command safe to run in a project where files were deleted by mistake.

Template structure

AGENTS.md

templates/AGENTS.md is a composition file. Lines starting with @templates/ are replaced by the referenced file. Blocks between <!-- opts --> and <!-- /opts --> are selectable options.

templates/AGENTS.md
├── AGENTS.md.general.guidance        always included
├── ## Project structure              user-owned
├── ## Common tasks                   user-owned
├── ## Environment & tooling
│   └── AGENTS.md.tooling.*           selectable
└── ## Coding conventions
    └── AGENTS.md.conventions.*       selectable

The parts are grouped by prefix:

Prefix Meaning
AGENTS.md.general.* Always included.
AGENTS.md.tooling.* Selectable under ## Environment & tooling.
AGENTS.md.conventions.* Selectable under ## Coding conventions.

To add a new optional section, create templates/AGENTS.md.tooling.<name> and reference it inside the <!-- opts --> block.

.gitignore

.gitignore.template follows the same pattern:

.gitignore.template
├── gitignore.taskfile                always included
├── <!-- opts -->
│   ├── gitignore.hugo
│   ├── gitignore.jupyter
│   ├── gitignore.pnpm
│   ├── gitignore.obsidian
│   ├── gitignore.python
│   └── gitignore.zensical
└── # Project                         user-owned

The # Taskfile block is always present. The # Project block is reserved for project-specific entries.

What is preserved on update

update-project never replaces a whole file. It merges the template into the target.

task

Preserved Replaced
Your help-table() rows. Everything before help-table().
Your custom functions and static vars. help().
Your dispatch block. The dispatch block at the end.

The command locates help-table(), help() and the dispatch block in both files and splices the template header and dispatch around your code. If any of these blocks is missing, the update aborts without writing.

AGENTS.md (--agents)

Preserved Replaced
Content of ## Project structure. AGENTS.md.general.guidance.
Content of ## Common tasks. All selected tooling.* and conventions.* parts.

## Common tasks is rendered inside the ## Project structure block. A legacy top-level ## Common tasks section is migrated into it and the standalone heading is dropped.

Changes to the parts in templates/ are applied on the next update. Edits you make directly to a template-owned section are lost.

.gitignore (--gitignore)

Preserved Replaced
Entries under # Project. The # Taskfile block.
All selected option blocks.

What is not preserved

  • Template-owned sections. ## General agent guidance, ## Environment & tooling, ## Coding conventions and their parts are regenerated from templates/.
  • task help rows for removed commands. Rows are kept as-is; update-project does not prune them.
  • Unselected options. Parts you did not select are not added. Selecting them later requires another run.
  • CHANGELOG.md, README.md and .env.template. update-project does not touch these files.
  • An existing LICENSE. It is never overwritten. The license dialog only appears when the file is missing, so a license is never switched by an update.

Keep templates in sync

When you change a part in templates/, run the update in the projects that use it:

task update-project --agents --gitignore

Review the diff before committing. The merge is line-based, so a manual edit inside a template-owned section is silently discarded.