HowToCook Project Structure and Organization: A Technical Deep Dive

The HowToCook repository employs a content-first architecture where Markdown recipes reside in categorized directories under dishes/ and tips/, while a Node.js automation script generates navigation indexes, difficulty ratings, and static-site configuration automatically.

The Anduin2017/HowToCook project demonstrates how a simple HowToCook project structure can scale to hundreds of recipes without manual maintenance. By storing culinary content as plain Markdown and leveraging a lightweight build pipeline, the repository maintains a clean, contributor-friendly organization while automatically generating complex navigation systems and difficulty classifications.

Repository Layout and Directory Structure

The repository organizes content, automation, and generated artifacts into distinct top-level directories. This separation ensures that contributors can focus on writing recipes while the build system handles navigation and formatting.

Core Content Directories

All human-authored content lives in two primary locations:

  • dishes/ – The main recipe collection organized by culinary category. Each subfolder represents a category (e.g., meat_dish/, vegetable_dish/, breakfast/, soup/) and contains individual dish folders with Markdown files and optional images. For example, dishes/meat_dish/黑椒牛柳/黑椒牛柳.md contains the recipe for Black Pepper Beef Tenderloin.

  • tips/ – Supplementary cooking knowledge including equipment guides, kitchen safety protocols, and advanced techniques. Files like tips/厨房准备.md provide foundational knowledge that supports the recipe collection.

Generated Navigation and Configuration Files

The HowToCook project structure relies on auto-generated files that should never be edited manually:

  • starsystem/ – Contains difficulty index files (0Star.md through 5Star.md) generated by counting Unicode star characters (★) in each recipe. These files are completely auto-generated based on star counts in recipe files.

  • README.md – The repository's human-readable entry point. This file is regenerated automatically to include categorized recipe lists, difficulty indexes, and contribution guidelines.

  • mkdocs.yml – Configuration file for the MkDocs static site generator, automatically updated to reflect the current directory structure for web deployment.

Build System and Templates

Automation logic and contributor onboarding resources reside in:

  • .github/readme-generate.js – The core Node.js script that orchestrates the entire build process, from scanning directories to rendering final output files.

  • dishes/template/示例菜/示例菜.md – The standardized recipe template that contributors copy when adding new dishes. This template includes commented sections for ingredients, measurements, cooking steps, and difficulty ratings.

  • .github/workflows/build.yml – GitHub Actions configuration that executes the build pipeline on every push to ensure documentation remains synchronized with content changes.

  • package.json – Declares Node.js runtime dependencies and build scripts, including linting tools like textlint and markdownlint-cli.

How the Build Automation Works

The repository maintains its HowToCook project structure through a lightweight but powerful Node.js automation pipeline. This system eliminates manual maintenance of navigation files while ensuring consistency across hundreds of recipes.

The readme-generate.js Script

Located at .github/readme-generate.js, this script serves as the central orchestrator for repository maintenance. It performs four critical operations without requiring external services or databases:

  1. Directory Scanning – The getAllMarkdown() function recursively traverses the repository tree, excluding node_modules and .git directories, to collect every .md file with its relative path.

  2. Content Classification – The script categorizes each file as either a tip (tips/), advanced tip (tips/advanced/), or specific dish category based on parent folder names (e.g., meat_dish/, vegetable_dish/).

  3. Star Rating Calculation – The organizeByStars() function processes each recipe to count difficulty indicators.

  4. Template Rendering – The script populates readme_template.md and mkdocs_template.yml with generated navigation sections, writing the final files to README.md and mkdocs.yml.

Scanning and Classification Logic

The build system distinguishes between different content types by analyzing file paths. During the scanning phase, the script builds a categories object that groups files into logical sections:

  • Recipes in dishes/breakfast/ populate the breakfast category
  • Files in tips/advanced/ populate the advanced techniques section
  • Each category maintains an array of file objects containing paths and metadata

This classification enables the template renderer to generate hierarchical navigation without hardcoding directory names.

Star Rating Index Generation

The difficulty classification system relies on the countStars() function to analyze recipe complexity:

async function countStars(filename) {
  const data = await fs.readFile(filename, 'utf-8');
  let stars = 0;
  const lines = data.split('\n');
  lines.forEach(line => {
    // Count every ★ character in the file
    stars += (line.match(//g) || []).length;
  });
  return stars;
}

When organizeByStars() processes the recipe collection, it aggregates files by their star count (0 through 5) and generates corresponding Markdown files in starsystem/. A recipe containing three stars appears in starsystem/3Star.md, while five-star recipes populate 5Star.md, creating a browsable difficulty ladder.

CI/CD Pipeline Integration

The .github/workflows/build.yml configuration ensures the HowToCook project structure remains synchronized automatically:


# Install dev dependencies (Node.js ≥ 14)

npm install

# Re-generate README and MkDocs files

npm run build

Every push to the repository triggers the GitHub Actions workflow, which executes readme-generate.js. If the script generates changes to README.md, mkdocs.yml, or star system files, the CI pipeline commits these updates automatically, ensuring navigation always reflects the current content state without manual intervention.

Adding a New Recipe to the Repository

Contributors interact with the HowToCook project structure through a standardized workflow that requires no knowledge of the build system. The process leverages the template system and relies on CI automation for integration.

Follow these steps to add a new dish:


# 1️⃣ Copy the template

cp -r dishes/template/示例菜 dishes/meat_dish/新菜名

# 2️⃣ Rename the Markdown file (keep the same name as the dish)

mv dishes/meat_dish/新菜名/示例菜.md dishes/meat_dish/新菜名/新菜名.md

# 3️⃣ Edit the file, delete the <!-- … --> comments and fill the sections

#    (ingredients, calculations, steps, difficulty ★ rating, etc.)

# 4️⃣ Commit & push – CI will rebuild README & star index automatically

git add dishes/meat_dish/新菜名
git commit -m "Add 新菜名 recipe"
git push

Because the build script recursively scans the dishes/ tree, the new recipe automatically appears in:

  • The category list in README.md under the appropriate section (e.g., "荤菜" for meat dishes)
  • The difficulty index (starsystem/XStar.md) based on the number of ★ characters in the file
  • The MkDocs navigation via the auto-generated mkdocs.yml configuration

Summary

  • The HowToCook project structure maintains strict separation between human-authored content in dishes/ and tips/ and machine-generated navigation in README.md, starsystem/, and mkdocs.yml.
  • A single Node.js script (.github/readme-generate.js) automates all maintenance tasks, using getAllMarkdown() for directory scanning, organizeByStars() for difficulty classification, and template rendering for output generation.
  • Recipes use a standardized Markdown template with Unicode star characters (★) to indicate difficulty, which the build system counts via countStars() to generate browsable difficulty indexes.
  • GitHub Actions CI executes npm run build on every push, ensuring navigation files remain synchronized with content changes without manual intervention.

Frequently Asked Questions

What programming language powers the HowToCook build system?

The build automation is written in JavaScript (Node.js). The main script .github/readme-generate.js uses native Node.js modules such as fs/promises and path to scan directories, parse Markdown files, and generate static navigation files. The project requires no external build tools like Jekyll or Hugo, relying only on Node.js and a few dev-dependencies including textlint and markdownlint-cli.

How does the repository automatically categorize recipes by difficulty?

The system uses the countStars() function within readme-generate.js to scan each recipe file for Unicode star characters (★). It totals the count for each file and aggregates recipes into difficulty-specific Markdown files located in starsystem/ (e.g., 3Star.md for three-star recipes). This creates a browsable difficulty ladder ranging from 0 stars (simple) to 5 stars (complex) without requiring manual categorization by contributors.

Can I contribute a new recipe without manually editing the README?

Yes. Contributors only need to copy the template from dishes/template/示例菜/示例菜.md to the appropriate category folder (such as dishes/meat_dish/), fill in the recipe content including the difficulty rating using ★ characters, and commit the changes. The GitHub Actions workflow defined in .github/workflows/build.yml automatically runs npm run build, which executes readme-generate.js to regenerate README.md, mkdocs.yml, and the star rating indexes to include your new recipe.

What is the purpose of the mkdocs.yml file in the repository?

The mkdocs.yml file serves as the configuration for MkDocs, a static site generator that publishes the cookbook as a browsable website. It is auto-generated by the build script to reflect the current directory structure of recipes and tips, mapping Markdown content to navigation menus. This ensures the web version of the cookbook stays synchronized with the repository structure without requiring manual updates to the site configuration when new categories or recipes are added.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →