pjangler-dev

star 9

Create pjangler Commands and Recipes for project bootstrapping. Use when: (1) Creating a new Command class to add/generate files or directories (2) Creating a new Recipe that composes multiple Commands (3) Registering new recipes in the CLI (4) Adding new subsystem bootstrapping functionality Triggers: "pjangler command", "pjangler recipe", "add subsystem", "bootstrap", "project scaffolding"

delorenj By delorenj schedule Updated 2/10/2026

name: pjangler-dev description: | Create pjangler Commands and Recipes for project bootstrapping. Use when: (1) Creating a new Command class to add/generate files or directories (2) Creating a new Recipe that composes multiple Commands (3) Registering new recipes in the CLI (4) Adding new subsystem bootstrapping functionality Triggers: "pjangler command", "pjangler recipe", "add subsystem", "bootstrap", "project scaffolding"

Pjangler Development

Pjangler uses a Command Pattern architecture where Commands are atomic operations and Recipes compose Commands into subsystem bootstrappers.

Architecture Overview

src/
├── commands/           # Atomic file/directory operations
│   ├── Command.ts      # Base class with helpers
│   └── Add*.ts         # Individual commands
├── recipes/            # Composed command sequences
│   ├── Recipe.ts       # Base class with execution logic
│   └── *Recipe.ts      # Subsystem recipes
└── index.ts            # CLI entry point

Creating a Command

Commands are atomic operations that create files or directories.

Step 1: Create the Command File

Create src/commands/Add<Name>.ts:

import { Command, InvokeResult } from "./Command";

export class Add<Name> extends Command {
  async invoke(): Promise<InvokeResult> {
    const filePath = "<target-file>";

    // Check existing (skip if exists unless force)
    if (this.fileExists(filePath) && !this.context.force) {
      return {
        success: false,
        message: "⚠️  <file> already exists",
        filePath
      };
    }

    const content = `<file-content>`;

    this.writeFile(filePath, content);
    return {
      success: true,
      message: "✅ Created <file>",
      filePath
    };
  }
}

Available Helpers

The Command base class provides:

  • this.context.targetDir - Target directory path
  • this.context.force - Whether to overwrite existing files
  • this.fileExists(path) - Check if file exists relative to targetDir
  • this.writeFile(path, content) - Write file, creating dirs as needed
  • this.createDirectory(path) - Create directory structure

Command Patterns

File creation (most common):

async invoke(): Promise<InvokeResult> {
  const filePath = "config.json";
  if (this.fileExists(filePath) && !this.context.force) {
    return { success: false, message: "⚠️  config.json already exists", filePath };
  }
  this.writeFile(filePath, `{"key": "value"}`);
  return { success: true, message: "✅ Created config.json", filePath };
}

Directory creation:

async invoke(): Promise<InvokeResult> {
  this.createDirectory("src/components");
  return { success: true, message: "✅ Created src/components/", filePath: "src/components" };
}

Multiple files (export multiple classes from one file):

export class AddPackageJson extends Command { ... }
export class AddReadme extends Command { ... }
export class AddSrcDirectory extends Command { ... }

Creating a Recipe

Recipes compose Commands into subsystem bootstrappers.

Step 1: Create the Recipe File

Create src/recipes/<Name>Recipe.ts:

import { Recipe } from "./Recipe";
import { AddSomeFile } from "../commands/AddSomeFile";
import { AddAnotherFile } from "../commands/AddAnotherFile";
import type { CommandContext } from "../commands/Command";

export class <Name>Recipe extends Recipe {
  constructor(context: CommandContext) {
    super(context);
    this
      .addIngredient(AddSomeFile)
      .addIngredient(AddAnotherFile);
  }

  protected printNextSteps(): void {
    console.log("🎉 <Name> subsystem initialized!");
    console.log("   Next steps:");
    console.log("   1. <first step>");
    console.log("   2. <second step>");
  }
}

Step 2: Register in CLI

Add to src/index.ts:

import { <Name>Recipe } from "./recipes/<Name>Recipe";

// In the switch statement:
case "<name>":
  const recipe = new <Name>Recipe(context);
  await recipe.execute();
  break;

Update the list command output to include the new subsystem.

File Naming Conventions

Type Pattern Example
Command Add<Target>.ts AddDockerfile.ts
Recipe <Subsystem>Recipe.ts DockerRecipe.ts
Multi-command file <Domain>Commands.ts NodeCommands.ts

Testing Commands

Run manually to verify:

cd /tmp/test-project
bun /home/delorenj/code/pjangler/src/index.ts init <subsystem>

Check generated files match expectations.

Reference

For detailed interfaces and examples, see:

Install via CLI
npx skills add https://github.com/delorenj/skills --skill pjangler-dev
Repository Details
star Stars 9
call_split Forks 1
navigation Branch main
article Path SKILL.md
More from Creator