init-repo

Scaffolds a new project repository for agentic development from a problem description, or sets up ops tooling (git, precommits, gitignore, licensing, CI) for an existing project. Guides the user through naming, runtime, package manager, devops, licensing, and project structure. Use when the user says "init project", "new project", "start a project", "scaffold repo", "create repo", or describes a problem they want to build a solution for.

Safety Notice

This listing is imported from skills.sh public index metadata. Review upstream SKILL.md and repository scripts before running.

Copy this and send it to your AI assistant to learn

Install skill "init-repo" with this command: npx skills add nathan13888/nice-skills/nathan13888-nice-skills-init-repo

Initializing Project

Scaffold a new project repository optimized for agentic development from a problem description -- or just set up ops tooling (git, precommits, gitignore, licensing, etc.) for an existing or empty project.

Quick Start

When invoked, follow the workflow below sequentially. Use AskUserQuestion at each decision point to gather user preferences. Do NOT skip steps or assume defaults without asking.

State Variables

Track these variables throughout the entire workflow. Once set, use the stored value -- never hardcode a branch name like main or master.

VariableSet inDescription
{DEFAULT_BRANCH}Step 0 or Step 8The repository's default branch name (e.g., main, master, develop). Every later step that references a branch MUST use this variable.

Workflow

Step 0: Detect Environment

Before anything else, check the current directory's state:

  1. Run git rev-parse --is-inside-work-tree to see if the CWD is already inside a git repository (even if it has zero commits or is otherwise empty).
  2. Run ls -A to check if the directory has any files/folders at all.
  3. If it IS a git repo, note this -- we will NOT run git init later. Run git symbolic-ref --short HEAD to detect the current branch name.
  4. If it is NOT a git repo, note this -- we may need to initialize one later. {DEFAULT_BRANCH} will be determined in Step 8.

Tell the user what you detected:

  • Whether the current directory is a git repo
  • Whether it's empty or has existing files

If it IS a git repo, also confirm the default branch with the user:

I detected the current branch is {detected branch}. What is the default branch for this repository? (default: {detected branch})

Store the user's answer (or confirmed default) as {DEFAULT_BRANCH}. This is critical -- the value will be reused in CI/CD triggers, push commands, and other steps.

Then ask explicitly:

Where do you want to set up the project?

  1. Here -- use the current directory ({CWD})
  2. New subdirectory -- create a new folder inside the current directory

If the user picks "New subdirectory", ask for the folder name, create it, and cd into it. All subsequent operations MUST happen in the chosen directory -- never in a parent or sibling directory.

Step 1: Understand the Problem

Read the user's problem description. If none was provided, ask:

What problem are you solving? Describe what you want to build in 1-2 sentences.

Summarize back your understanding before proceeding.

Step 1.5: Scaffolding Mode

Ask the user what level of scaffolding they want:

What would you like to set up?

  1. Full project -- scaffold code, tooling, and ops (runtime, package manager, formatter, linter, CI, license, precommits, CLAUDE.md)
  2. Ops only -- just set up ops tooling (git, .gitignore, license, CI, precommits, CLAUDE.md) without creating project code or installing a runtime/package manager

If the user picks Ops only, skip Steps 2-5 entirely and jump straight to Step 6 (CI/CD). The ops-only path still walks through CI, licensing, git setup, gitignore, precommits, and CLAUDE.md.

If the user picks Full project, continue with Step 2.

Step 2: Project Name

Suggest 2-3 kebab-case project names derived from the problem description. Ask the user to pick one or provide their own.

Naming rules:

  • Lowercase, kebab-case (my-project-name)
  • Short (1-3 words)
  • Descriptive of the solution, not the problem

Step 3: Runtime & Language

Ask the user which runtime/language to use. Present options based on what fits the problem:

OptionWhen to suggest
TypeScript (Bun)Web apps, APIs, CLI tools, full-stack; fast runtime with built-in bundler/test runner
TypeScript (Node.js)Web apps, APIs, CLI tools, full-stack; broader ecosystem compatibility
PythonData, ML/AI, scripting, automation
RustPerformance-critical, systems, CLI tools
GoInfrastructure, networking, microservices

Suggest the best fit as the first option with "(Recommended)" appended.

Step 4: Package Manager & Project Init

Based on the chosen runtime, initialize the project:

TypeScript (Bun) (Recommended for TypeScript):

  • Run bun init
  • Create tsconfig.json with strict mode

TypeScript (Node.js):

  • Ask: npm, yarn, or pnpm? (Recommend pnpm)
  • Run the appropriate init command
  • Create tsconfig.json with strict mode

Python:

  • Ask: uv, poetry, or pip? (Recommend uv)
  • Run the appropriate init command
  • Set Python version (ask or default to 3.12+)

Rust:

  • Run cargo init
  • Create rust-toolchain.toml to pin the toolchain and ensure all contributors have formatting/linting/editor components:
[toolchain]
channel = "stable"
components = ["rustfmt", "clippy", "rust-analyzer"]

Go:

  • Ask for module path (suggest github.com/{user}/{project})
  • Run go mod init

Step 5: Code Formatting & Linting

Ask the user which formatter and linter to use. Present options based on the chosen runtime. The user may select separate tools for formatting and linting, or a unified tool that handles both.

TypeScript / JavaScript:

OptionTypeDescription
Biome (Recommended)Formatter + LinterFast, unified tool, minimal config
ESLint + PrettierLinter + FormatterMost popular, huge plugin ecosystem
ESLint (flat config)Linter onlyIf user wants linting without a formatter
oxlintLinterExtremely fast, Rust-based, drop-in ESLint alternative

Python:

OptionTypeDescription
Ruff (Recommended)Formatter + LinterExtremely fast, replaces Black + Flake8 + isort
Black + Flake8Formatter + LinterEstablished, widely adopted
Black + RuffFormatter + LinterBlack formatting with Ruff linting

Rust:

OptionTypeDescription
rustfmt + Clippy (Recommended)Formatter + LinterStandard Rust toolchain, no extra install

Go:

OptionTypeDescription
gofmt + go vet (Recommended)Formatter + LinterBuilt into Go toolchain
gofmt + golangci-lintFormatter + LinterMore comprehensive linting rules

After selection:

  1. Install the chosen tools as dev dependencies
  2. Create the appropriate config file(s) (e.g., biome.json, ruff.toml, .eslintrc, rustfmt.toml)
  3. Add format, lint, and lint:fix scripts to the project's task runner (e.g., package.json scripts, Makefile, Justfile)

Step 6: CI/CD

Ask the user what CI/CD they want. Options:

OptionDescription
GitHub Actions (Recommended)Standard for GitHub repos
NoneSkip CI/CD for now
OtherLet user specify

If GitHub Actions is selected, create .github/workflows/ci.yml with:

  • Format check step (e.g., biome check, ruff format --check, cargo fmt --check)
  • Lint step (using the linter chosen in Step 5)
  • Test step (appropriate test runner)
  • Triggered on push to {DEFAULT_BRANCH} and pull requests (use the exact branch name stored earlier -- do NOT hardcode main)

Note: The workflow file is created locally. The user must push the repository to GitHub and verify the workflow runs. Any required secrets (e.g., GITHUB_TOKEN, deployment keys) must be configured in the repository's Settings -> Secrets and variables -> Actions.

Step 7: Licensing

Ask the user which license to use. Present the common options prominently:

OptionSPDX IDCategoryWhen to suggest
MITMITPermissiveMost common open-source license
Apache 2.0Apache-2.0PermissiveOpen source with patent protection
GPL 3.0GPL-3.0CopyleftRequires derivative works stay open
Dual License(see below)PermissiveTwo licenses (e.g., MIT + Apache-2.0, Rust standard)
Proprietary----Private/commercial projects
None----Skip for now
Other(see below)--Pick from expanded list
<details> <summary>Expanded license list (click to show)</summary>

Permissive: MIT . MIT-0 . Apache-2.0 . BSD-2-Clause . BSD-3-Clause . BSD-3-Clause-Clear . ISC . 0BSD . Unlicense . Zlib . CC0-1.0 . UPL-1.0

Copyleft: GPL-2.0 . GPL-3.0 . LGPL-2.1 . LGPL-3.0 . AGPL-3.0 . MPL-2.0 . EPL-1.0 . EPL-2.0 . EUPL-1.2 . OSL-3.0

Source-available: BSL-1.0

Other: CC-BY-4.0 . CC-BY-SA-4.0 . OFL-1.1 . MulanPSL-2.0 . WTFPL

</details>

Fetching License Text

Fetch the license text using WebFetch from this skill's vendored license templates:

https://raw.githubusercontent.com/Nathan13888/nice-skills/master/data/licenses/{SPDX-ID}

After reading, replace placeholder fields with actual values:

  • <year> or [year] -> current year
  • <copyright holders> or [fullname] -> user's name from git config user.name (ask if not set)

Single License

  1. Fetch the license text from the URL above
  2. Replace placeholders
  3. Write to LICENSE

Dual License

When the user selects Dual License:

  1. Ask which two licenses to combine (recommend MIT + Apache-2.0, the Rust ecosystem standard)
  2. Fetch both license texts in parallel via WebFetch
  3. Replace placeholders in both
  4. Create LICENSE-MIT and LICENSE-APACHE (pattern: LICENSE-{SHORT-NAME})
  5. Create a root LICENSE file explaining the dual licensing:
This project is licensed under either of

  * Apache License, Version 2.0 (LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0)
  * MIT License (LICENSE-MIT or http://opensource.org/licenses/MIT)

at your option.

Step 8: Git Setup

Use the git repo status detected in Step 0 -- do NOT re-run the check.

If no repo was detected in Step 0:

  1. Ask the user what the default branch name should be (suggest main as the default, but accept any name such as master, develop, trunk, etc.). Store the answer as {DEFAULT_BRANCH} -- this value is used in CI/CD triggers (Step 6) and the final push command (Step 11).
  2. Run git init -b {DEFAULT_BRANCH} to initialize with that branch name.
  3. Create .gitignore (see below)
  4. Create initial commit: chore: initialize project

If a repo already exists (detected in Step 0):

  1. Ask the user if they want a .gitignore created or updated
  2. If in Ops only mode and no runtime was chosen, ask the user which .gitignore template(s) to use (or offer to skip)
  3. Ask the user if they want an initial commit with the scaffolded files

Fetching .gitignore Templates

Fetch the primary .gitignore template for the chosen runtime using WebFetch:

RuntimeTemplateURL
TypeScript (Bun/Node)Nodehttps://raw.githubusercontent.com/github/gitignore/b4105e73e493bb7a20b5d7ea35efd5780ca44938/Node.gitignore
PythonPythonhttps://raw.githubusercontent.com/github/gitignore/b4105e73e493bb7a20b5d7ea35efd5780ca44938/Python.gitignore
RustRusthttps://raw.githubusercontent.com/github/gitignore/b4105e73e493bb7a20b5d7ea35efd5780ca44938/Rust.gitignore
GoGohttps://raw.githubusercontent.com/github/gitignore/b4105e73e493bb7a20b5d7ea35efd5780ca44938/Go.gitignore

After fetching the primary template, ask the user if they want additional global ignores appended:

OptionTemplate Name
macOSmacOS
LinuxLinux
WindowsWindows
VSCodeVisualStudioCode
JetBrainsJetBrains
VimVim
None(skip)

Global URL pattern: https://raw.githubusercontent.com/github/gitignore/b4105e73e493bb7a20b5d7ea35efd5780ca44938/Global/{Name}.gitignore

Combine templates into a single .gitignore with section headers:

# === Node ===
{fetched Node.gitignore content}

# === macOS ===
{fetched macOS.gitignore content}

Step 9: Git Hooks

Ask the user if they want git hooks to enforce code quality. Options:

OptionDescription
Yes, with Lefthook (Recommended)Universal git hooks manager; works with any language/runtime
Yes, with native hooksLanguage-specific setup (husky, pre-commit framework, .git/hooks)
NoSkip git hooks

The hooks follow this convention:

HookAction
pre-commitAuto-fix formatting and linting on staged files
pre-pushCheck formatting and linting (no fix) + run tests

The rationale: pre-commit fixes what it can so the developer isn't blocked; pre-push is a final gate that catches anything unfixable and runs the full test suite before code reaches the remote.

Lefthook (universal, any runtime)

Lefthook is a fast, language-agnostic git hooks manager that works for any runtime.

  1. Install lefthook (pick the method appropriate for the project):
    • npm/bun: npm install --save-dev lefthook / bun add -d lefthook
    • Homebrew: brew install lefthook
    • Go: go install github.com/evilmartians/lefthook@latest
    • Or download a binary release from GitHub
  2. Create lefthook.yml at the project root. Substitute the actual commands for the chosen runtime and formatter/linter:
pre-commit:
  commands:
    format-fix:
      run: {format fix command}   # e.g. biome format --write, ruff format, cargo fmt
    lint-fix:
      run: {lint fix command}     # e.g. biome lint --fix, ruff check --fix, cargo clippy --fix

pre-push:
  commands:
    format-check:
      run: {format check command} # e.g. biome format --check, ruff format --check, cargo fmt --check
    lint-check:
      run: {lint check command}   # e.g. biome lint, ruff check, cargo clippy -- -D warnings
    test:
      run: {test command}         # e.g. bun test, pytest, cargo test, go test ./...
  1. Run lefthook install to activate the hooks.

Native hooks (language-specific)

If the user prefers native hooks instead:

TypeScript (Bun/Node.js):

  • Install husky and lint-staged
  • Configure lint-staged in package.json to run the formatter/linter fix commands on staged files (auto-fix on commit)
  • Initialize husky with:
    • pre-commit hook: runs lint-staged (auto-fixes staged files)
    • pre-push hook: runs format check, lint check, and tests

Python:

  • Install pre-commit framework
  • Create .pre-commit-config.yaml with hooks that fix (e.g., ruff format, ruff check --fix)
  • Run pre-commit install --hook-type pre-commit --hook-type pre-push
  • Add a pre-push stage entry (or a separate .git/hooks/pre-push script) that runs format check, lint check, and pytest

Rust:

  • Create .git/hooks/pre-commit: runs cargo fmt (fix) and cargo clippy --fix
  • Create .git/hooks/pre-push: runs cargo fmt --check, cargo clippy -- -D warnings, and cargo test
  • Make both scripts executable (chmod +x)

Go:

  • Create .git/hooks/pre-commit: runs gofmt -w . (fix) and applies golangci-lint run --fix if available
  • Create .git/hooks/pre-push: runs gofmt -l . (check), go vet ./..., and go test ./...
  • Make both scripts executable (chmod +x)

Step 10: CLAUDE.md

Ask the user if they want an agent context file created for the project. Options:

OptionDescription
Yes, as CLAUDE.mdGives Claude context about the project for agentic development
**Yes, as AGENTS.md + symlink ** (recommended)Creates AGENTS.md as the canonical file and symlinks CLAUDE.md -> AGENTS.md (preferred for multi-agent/tool setups)
NoSkip

If the user picks AGENTS.md + symlink, create the file as AGENTS.md and then run:

ln -s AGENTS.md CLAUDE.md

Regardless of which option is chosen, the file content is identical -- use the template below, filling in project-specific details:

# {Project Name}

{One-line problem description}

## Tech Stack

- **Runtime:** {runtime}
- **Language:** {language}
- **Package Manager:** {package manager}
- **Formatter:** {formatter}
- **Linter:** {linter}

## Project Structure

{tree of created files/dirs}


## Development

### Setup

```bash
{install command}

Run

{run/dev command}

Test

{test command}

Format

{format command}

Lint

{lint command}

Lint Fix

{lint fix command}

Conventions

  • {Language-specific conventions, e.g., "Use strict TypeScript - no any types"}
  • Write tests for all new functionality
  • Use conventional commits (type: description)
  • Keep functions small and focused

Architecture

{Brief description of intended architecture based on the problem}


### Step 11: Summary

Print a summary of everything that was created. Adapt the summary to the chosen mode:

**Full project mode:**

Project initialized: {name} Location: {path} Runtime: {runtime} Package Manager: {pkg manager} Formatter: {formatter} Linter: {linter} License: {license(s)} CI/CD: {ci/cd} Pre-commit: {yes/no}

Files created: {list of files -- if AGENTS.md + symlink was chosen, show both AGENTS.md and CLAUDE.md -> AGENTS.md}

Next steps:

  1. {install command}
  2. Push to GitHub and verify GitHub Actions workflows run correctly
    • Configure any required secrets in Settings -> Secrets and variables -> Actions
  3. Start building!

**Ops only mode:**

Ops tooling initialized Location: {path} License: {license(s)} CI/CD: {ci/cd} Pre-commit: {yes/no}

Files created: {list of files -- if AGENTS.md + symlink was chosen, show both AGENTS.md and CLAUDE.md -> AGENTS.md}

Next steps:

  1. Push to GitHub and verify GitHub Actions workflows run correctly
    • Configure any required secrets in Settings -> Secrets and variables -> Actions
  2. Start building!

> **Reminder:** GitHub Actions workflows only run once the repository is pushed to GitHub. If you haven't created the remote repository yet, do that first (`gh repo create` or via the GitHub UI), then push with `git push -u origin {DEFAULT_BRANCH}`. **Use the exact `{DEFAULT_BRANCH}` value confirmed/set earlier -- do NOT substitute `main` or any other name.**

If the project was created in the current directory, do NOT include a `cd` step -- the user is already there.

## Guidelines

- Always ask before creating files -- never assume preferences
- Use `AskUserQuestion` with concrete options, not open-ended prompts
- If a tool is not installed (e.g., `bun`, `uv`), offer to install it or suggest an alternative
- **All files MUST be created in the chosen project directory (CWD or the user's subdirectory choice from Step 0) -- never in a parent, sibling, or unrelated directory**
- Check if the target directory already exists before creating anything
- Keep the initial project minimal -- don't over-scaffold
- Respect the user's choice to skip code scaffolding -- ops-only mode is a first-class path, not a fallback
- The CLAUDE.md should be practical and specific, not boilerplate
- Detect git user.name and user.email from git config for license attribution
- If the user provides a GitHub username, use it for module paths and license
- Use `WebFetch` with prompt "Return the full file content exactly as-is" to get raw template text without summarization
- If `WebFetch` fails for any URL, fall back to generating content from memory and inform the user
- For dual-license, fetch both license texts in parallel to minimize latency

Source Transparency

This detail page is rendered from real SKILL.md content. Trust labels are metadata-based hints, not a safety guarantee.

Related Skills

Related by shared tags or category signals.

General

doc-n-fix

No summary provided by upstream source.

Repository SourceNeeds Review
General

wtf

No summary provided by upstream source.

Repository SourceNeeds Review
General

check

No summary provided by upstream source.

Repository SourceNeeds Review
General

sus

No summary provided by upstream source.

Repository SourceNeeds Review