# Learn a new template (auto-detects post-config tasks)
pt learn /path/to/PROJECT
# Update an existing template (use current directory if no path given)
pt update <template_name>
pt update <template_name> /path/to/PROJECT
# Ignore specific folders during learning
pt learn /path/to/PROJECT --ignore=DAILIES/*,PARKING_LOT/*,REFERENCE/*
# Ignore a folder name at any depth
pt learn /path/to/PROJECT --ignore=**/.godot/
# Non-interactive mode (useful for AI agents)
pt learn /path/to/PROJECT --name my_template --desc "My new template" --yespt learn supports learning templates directly from a remote Git repository or tarball archive by passing an http:// or https:// URL. Security is enforced: only downloads from trustedSources (configured in ~/.pt/config.yaml) are allowed by default. Untrusted sources trigger a warning and require explicit confirmation.
# Learn a template directly from a GitHub repository
pt learn https://github.com/username/my-template- URL Translation: If a GitHub or Gitea URL is provided,
ptautomatically translates the repository URL to its corresponding tarball download endpoint (e.g.,/archive/refs/heads/main.tar.gz). - Security Verification: Downloads are restricted to trusted sources (configured in
~/.pt/config.yaml). Untrusted sources trigger a warning and require explicit confirmation. - Download & Extraction: The tool downloads the archive into a secure temporary folder and extracts it. File size is validated (max 50MB).
- Template Discovery: The extracted directory is scanned for metadata (
.pt-template.json,template.json,.info.md,post_config.sh,post_config.bat) and variable placeholders ({{ var }}), matching local learn functionality exactly. - Save Config: The template config (skeleton structure, files, variables) is saved to the local configuration, pointing to the temporary folder as the
templateRoot.
During pt learn or pt update, the tool automatically scans text files at the root and in the first-level subdirectories for variable placeholders using the {{ variable_name }} syntax.
- Detection Range: Root files and 1st-level subfolder files (e.g.,
README.md,.makerc,DOC/closedown.md). - Registration: Any detected variables are automatically added to the template's configuration with default prompts (e.g.,
Enter variable_name:). - Global Suggestions: Your global variables (defined in
~/.pt/config.yaml) are automatically injected as additional suggestions during the learn process. - Updating: You can add new placeholders to a project folder and run
pt update <template_name>to automatically register them in your existing template.
Starting with v0.36.0, pt automatically scans parent directories for .env files and uses their values as defaults during initialization. This enables powerful configuration patterns:
# Create a .env file in your project directory
echo "prefix='rst_'" > .env
echo "project='MyProject'" >> .env
# Initialize a project - variables are pre-filled from .env
pt init my-template my-new-projectKey Features:
- Automatic Scanning: Scans up to 3 parent directories for
.envfiles - Variable Pre-filling: Values from
.envare used as defaults in prompts - Nested Variables: Supports nested placeholders like
prefix='app_{{ env }}' - Override Support: Use
--varsto override.envvalues:--vars project=OverriddenProject
Example with Nested Variables:
# .env file
prefix='app_{{ env }}'
env=prod
project=MyApp
# Template README.md.tmpl
# Content: {{prefix}}_{{project}}
# Result: app_prod_MyAppSecurity Note: .env files are not committed to version control. Use .gitignore to exclude them:
# .gitignore
.env
*.envThe pt CLI now supports nested variable expansion — variables can contain other variable placeholders that are resolved iteratively. This enables powerful configuration patterns:
# In .env file:
prefix='rst_{{ project }}'
project=MyProject
# During initialization, the system will:
# 1. Load prefix='rst_{{ project }}' from .env
# 2. Detect that prefix contains a {{ project }} placeholder
# 3. Resolve {{ project }} to MyProject
# 4. Set prefix to rst_MyProjectUse Cases:
- Project naming conventions:
prefix='app_{{ env }}'+env=prod→app_prod - Path templates:
template_path='docs/{{ project }}'+project=wiki→docs/wiki - Multi-level configurations: Combine multiple
.envfiles with nested references
How it works:
- Variables are expanded iteratively (up to 10 passes) to prevent infinite loops
- Circular references are detected and stopped gracefully
- Missing nested variables remain as
{{ variable }}placeholders - Whitespace is preserved:
{{ unknown }}stays as{{ unknown }}(not{{unknown}})
# Initialize from a template (auto-suggests post-config tasks)
pt init <template_name> /path/to/new/PROJECT
# Skip post-config tasks
pt init <template_name> /path/to/new/PROJECT --skip-post-config
# Dry run (preview actions without execution)
pt init <template_name> /path/to/new/PROJECT --dry-run
# Non-interactive mode with variables (useful for an API or AI agents)
pt init <template_name> /path/to/new/PROJECT --yes --vars project_name=foo,author=bar
# Initialize directly from a JSON template file (no config.yaml registration)
pt init /path/to/new/PROJECT --file my-template.json --yesThe --file option allows you to scaffold a project directly from a JSON template file without registering it in your local ~/.pt/config.yaml. This is ideal for:
- One-off project creation from a shared template
- CI/CD pipelines where you don't want to modify the user's config
- Receiving a template JSON from a colleague and using it immediately
# The template name is read from the JSON's "name" field
pt init ./new-project --file template.json --yes
# With variable overrides
pt init ./new-project --file template.json --yes --vars client=Acme,author=Jane# Remove a learned template (asks for confirmation)
pt remove <template_name>
# Short alias
pt rm <template_name>pt configShows all templates, their post_config tasks (if any), source paths, global post-config tasks, ignore patterns, global variables, and an example post-config block.
Global variables serve as boilerplate suggestions during the pt learn process.
# List global variables
pt variables
# Set/Update global variables (comma-separated pairs)
pt variables --set AUTHOR="Gary Ritchie",LICENSE="MIT"
# Delete a global variable
pt variables --delete LICENSEFor more details on how these are used, see the Configuration Guide.
You can share your templates with others simply by sharing a directory (or a ZIP of it). When someone else runs pt learn on it, pt will automatically detect the following files at the root:
.pt-template.jsonortemplate.json: Full template configuration — name, description, variables (with prompts, defaults, required flags), folders, copy_files, post_config, and post_copy. This is the most complete and portable way to share templates..info.md: Used to automatically set the template's name (from the first# Heading) and description.post_config.shorpost_config.bat: Parsed to automatically populate thepost_configactions in the user'sconfig.yaml.
Priority order: .pt-template.json > template.json > .info.md > post_config.sh/.bat. JSON config files take precedence over .info.md for name/description and over shell scripts for post_config tasks.
These files are also automatically generated at the root of a new project whenever you run pt init, making it trivial to initialize a project, zip it up, and share it with teammates as a fully-featured template!
The JSON template config file is the recommended way to make a template directory fully self-describing and portable. Place it at the root of your template directory:
{
"name": "my-web-app",
"description": "A Node.js web application with Express",
"variables": [
{
"name": "project_name",
"prompt": "Project name:",
"default": "my-app",
"required": true
},
{ "name": "author", "prompt": "Author name:", "default": "" }
],
"folders": [
{ "name": "src", "children": [] },
{ "name": "tests", "children": [] }
],
"copy_files": [
{
"src": "package.json",
"dest": "package.json",
"substitute_variables": true
},
{ "src": "README.md", "dest": "README.md", "substitute_variables": true }
],
"post_config": [
{ "command": "git init", "description": "Initialize git repository" },
{ "command": "npm install", "description": "Install dependencies" }
],
"post_copy": [{ "src": "bin/start.sh", "dest": "bin/start.sh" }]
}When pt learn encounters this file, all fields are used as pre-configured defaults, skipping the corresponding interactive prompts. Any fields not specified in the JSON file will fall back to normal auto-detection (file scanning, executable detection, etc.).
The complete workflow for sharing a fully portable template:
# 1. Export an existing template to JSON
pt config my-template --json > .pt-template.json
# 2. Place the JSON file at the root of your template directory
cp .pt-template.json /path/to/template-dir/
# 3. Share the directory (zip, git, etc.)
# 4. Recipient learns the template — all metadata auto-detected
pt learn /path/to/template-dir --yes
# 5. Or scaffold directly without registering in config
pt init ./new-project --file .pt-template.json --yesFor a more portable, text-based approach, you can export and import templates as JSON strings or files.
To export an existing template from your configuration as JSON:
pt config <template_name> --json > my_template.jsonTo add a template from a JSON file:
pt add <template_name> --file my_template.jsonOr from a JSON string:
pt add <template_name> '{"description":"My Template","files":{...}}'To scaffold a project directly from a JSON file without adding the template to your config:
pt init ./destination --file my_template.json --yesTo see your entire configuration (including all templates) in JSON format:
pt config --json