1
0
Fork 0
2 Egg creation checklist
Damien FLETY edited this page 2026-04-12 20:47:52 +00:00
This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

Egg Creation Checklist & Best Practices

This is your complete checklist for creating professional, working eggs. Use this as a final review before sharing your egg with the community!

📋 Pre-Creation Checklist

Before you start building your egg, make sure you have:

  • A text editor (VS Code, Notepad++, or Notepad)
  • An existing egg to reference (optional but helpful)
  • Knowledge of what you're creating (game, bot, app)
  • Understanding of the Egg Basics
  • List of variables you want users to customize

🏗️ Structure & Metadata Checklist

Required Fields

  • "meta": { "version": "PTDL_v2" } - Always required
  • "name" - Clear, descriptive egg name
  • "author" - Your name or email
  • "description" - What does this egg do?
  • "docker_images" - At least one valid image
  • "file_denylist" - Usually [] (empty array)

Good Practices

  • Name is concise (under 50 characters)
  • Description explains what the egg does
  • Author information is included
  • Docker images are actual, working images
  • No typos in metadata
  • Description mentions any requirements (games, knowledge, etc.)

Example:

{
  "name": "Counter-Strike 2",
  "author": "admin@example.com",
  "description": "A Counter-Strike 2 game server using SteamCMD",
  "meta": {
    "version": "PTDL_v2"
  }
}

🐳 Docker Image Checklist

  • Chosen appropriate base image (ubuntu, nodejs, java, steamcmd, etc.)
  • Image URL uses the correct registry (ghcr.io/ptero-eggs/yolks:* for runtime)
  • Installation container uses ghcr.io/ptero-eggs/installers:debian or :alpine
  • Image has all required software pre-installed
  • Provided multiple image options if applicable
  • Image documentation checked for any special requirements

Common Runtime Images:

  • Ubuntu: ghcr.io/ptero-eggs/yolks:ubuntu
  • Debian: ghcr.io/ptero-eggs/yolks:debian
  • Node.js: ghcr.io/ptero-eggs/yolks:nodejs_20
  • Java: ghcr.io/ptero-eggs/yolks:java_21
  • Python: ghcr.io/ptero-eggs/yolks:python_3.12
  • SteamCMD: ghcr.io/ptero-eggs/steamcmd:sniper

Common Installer Containers:

  • ghcr.io/ptero-eggs/installers:debian (use with bash)
  • ghcr.io/ptero-eggs/installers:alpine (use with ash)

⚙️ Variables Checklist

For Each Variable, Include ALL of These:

  • "name" - Human-readable name (e.g., "Server Name")
  • "description" - Clear explanation of what it does
  • "env_variable" - UPPERCASE with underscores (e.g., "SERVER_NAME")
  • "default_value" - Sensible default that works (always a string, even for numbers: "20" not 20)
  • "user_viewable" - Whether the user can see this variable (true or false)
  • "user_editable" - Whether the user can change this variable (true or false)
  • "rules" - Validation rules (e.g., "required|string|max:64")
  • "field_type" - Always "text" — no exceptions!

Important — field_type is ALWAYS "text": There are no other valid values. You do not use "number", "password", "boolean", or anything else. Instead, you express the type of data through the rules field:

  • Numbers: "rules": "required|numeric|between:1,64"
  • Booleans: "rules": "required|boolean" (use "0" / "1" as the default_value)
  • Optional strings: "rules": "nullable|string|max:64"
  • Required strings: "rules": "required|string|max:64"
  • URLs: "rules": "required|url"

Variable Best Practices:

  • Use UPPERCASE for variable names
  • Use underscores between words (SNAKE_CASE)
  • Descriptions tell users exactly what to enter
  • Default values actually work out of the box
  • No hardcoded values in startup/config
  • Related variables grouped together
  • Port numbers validated between 102465535
  • String lengths limited with max:

Variable Validation Examples:

  • Port numbers: "required|numeric|between:1024,65535"
  • Boolean flags: "required|boolean" with default "0" or "1"
  • Optional strings: "nullable|string|max:64"
  • Required fields: start with required|
  • Numeric ranges: use between:min,max
  • String lengths: use max:N

Complete variable example:

{
  "variables": [
    {
      "name": "Server Port",
      "description": "The port your server will run on (1024-65535)",
      "env_variable": "SERVER_PORT",
      "default_value": "25565",
      "user_viewable": true,
      "user_editable": true,
      "rules": "required|numeric|between:1024,65535",
      "field_type": "text"
    },
    {
      "name": "Max Players",
      "description": "Maximum number of players allowed (1-100)",
      "env_variable": "MAX_PLAYERS",
      "default_value": "20",
      "user_viewable": true,
      "user_editable": true,
      "rules": "required|numeric|between:1,100",
      "field_type": "text"
    }
  ]
}

🚀 Startup Command Checklist

  • Startup command is complete and valid
  • Variables use correct format: {{VARIABLE_NAME}} (in the startup field)
  • No hardcoded values (use variables instead)
  • Path separators correct for Linux (forward slashes)
  • Command tested locally if possible
  • Port uses {{server.build.default.port}} or a custom variable like {{SERVER_PORT}}
  • No typos in command syntax
  • Proper escaping for special characters
  • Runtime files are referenced as /home/container/... (not /mnt/server/...)

Good Example:

{
  "startup": "java -Xms128M -XX:MaxRAMPercentage=95.0 -jar {{SERVER_JARFILE}}"
}

Bad Example:

{
  "startup": "java -Xmx2048M -jar server.jar --port 25565 --name MyServer"
}

(Don't hardcode values — use variables instead!)

📝 Installation Script Checklist

  • Script is valid bash (or ash) syntax
  • Uses the correct shebang (#!/bin/bash for debian, #!/bin/ash for alpine)
  • Comments explain what each section does
  • Creates /mnt/server directory before writing files
  • Downloads required files correctly into /mnt/server
  • Sets proper file permissions
  • Handles errors gracefully
  • Variables are used (not hardcoded)
  • No interactive prompts (unattended install)
  • Prints status messages for user feedback
  • Creates default config files if needed
  • Tested and works from scratch

Path reminder: The installation script runs in its own container. Server files must go into /mnt/server. At runtime, the server container sees those same files at /home/container.

Script Best Practices:

  • Use meaningful variable names
  • Include error checking (if [ $? -eq 0 ])
  • Check if files already exist before overwriting
  • Handle missing dependencies
  • Provide clear status messages
  • Clean up temporary files
  • Don't use sudo (run as container user)

Example:

#!/bin/bash
echo "Installing MyApp..."

# Create server directory
mkdir -p /mnt/server
cd /mnt/server

# Download the application
wget https://example.com/app-latest.tar.gz

if [ $? -eq 0 ]; then
    echo "Download successful"
    tar -xzf app-latest.tar.gz
    rm app-latest.tar.gz
else
    echo "Error: Download failed"
    exit 1
fi

echo "Installation complete!"

🔧 Configuration Files Checklist

File Management:

  • Parser type matches file format (json, yaml, ini, properties, file)
  • File path is correct and matches where the file lives
  • File exists or is created during installation
  • Search strings are exact (case-sensitive!)
  • Replacement values use the correct variable format
  • In config.files parsers, variables use {{server.build.env.VARIABLE_NAME}}
  • In config.files parsers, the port uses {{server.build.default.port}}
  • Configuration file is valid JSON/YAML/etc. after modification

For Each Parser:

JSON:

  • Using dot notation for nested values (e.g., "database.host")
  • Quotes balanced properly
  • Valid JSON after modification

YAML:

  • Using spaces only (no tabs!)
  • Indentation consistent
  • Colon spacing correct (key: value)

INI:

  • Section names in brackets [section]
  • Using dot notation with section: section.key
  • Key=value format correct

Properties:

  • Simple key=value pairs
  • No sections
  • Keys match exactly

File (plain text):

  • Search string is exact and unique
  • Entire line being replaced correctly
  • No ambiguous search patterns

Example (decoded config.files value):

{
  "config.json": {
    "parser": "json",
    "find": {
      "server.port": "{{server.build.default.port}}",
      "server.name": "{{server.build.env.SERVER_NAME}}"
    }
  }
}

🎯 Startup Detection Checklist

  • Detection string appears in server output when it's ready
  • Detection string is unique (doesn't appear earlier during startup)
  • Detection string appears shortly after the server is ready
  • config.startup is a JSON-encoded string (not a raw object)
  • Format is correct: "{\"done\": \"Server is ready\"}"

Example (as it looks inside the egg JSON):

{
  "config": {
    "startup": "{\"done\": \"Server listening on port\"}",
    "files": "{}",
    "logs": "{}",
    "stop": "^C"
  }
}
  • All JSON is properly formatted
  • No broken references between sections
  • File paths use correct separators (/ not \)
  • All variables referenced in startup or config.files are defined in the variables array
  • No circular dependencies

📚 Documentation Checklist

https://git.flety.net/damien/pterodactyl-eggs/wiki/Home:

  • Explains what the egg does
  • Lists available settings and what they do
  • Shows how to use the egg
  • Mentions any special requirements
  • Includes examples if applicable
  • Clear instructions for first-time users
  • Links to official documentation if needed

Example README structure:

# My Game Server

## What This Egg Does
Brief description of the game/app.

## Requirements
- Minimum RAM: 2GB
- Recommended RAM: 4GB
- Disk space: 10GB

## Configuration
List of settings users can adjust:
- **Server Name**: Display name in server browser
- **Max Players**: Maximum concurrent players
- **Port**: Server port (default: 25565)

## Support
Where to get help if something breaks.

🧪 Testing Checklist

Before releasing your egg, test:

Installation:

  • Install from scratch completes successfully
  • All required files are downloaded correctly into /mnt/server
  • Permissions are set properly
  • Installation doesn't take too long (< 5 minutes normally)
  • Disk space requirements are reasonable
  • No errors in installation log

Startup:

  • Server starts successfully
  • Startup detection string appears in console output
  • Server is actually running (not just starting)
  • No errors in console output
  • Takes reasonable time to start (< 30 seconds normally)
  • Port is accessible from outside the container

Variables:

  • Changing a variable actually affects behavior
  • Default values work as-is without any changes
  • Invalid values are caught by validation rules
  • Special characters handled correctly
  • Port values actually change the port used

Configuration Files:

  • Configuration files are created/modified correctly at /home/container
  • Files are valid format after modification
  • Variables substituted properly
  • No leftover template syntax in files
  • File permissions allow the server to read/write

Edge Cases:

  • Install after already installed (if applicable)
  • Very long server names (near the max length)
  • Port numbers at edges (1024, 65535)
  • Zero values where numeric
  • Empty strings where optional
  • Unicode characters in names

🚨 Common Mistakes to Avoid

Hardcoding Values

Bad: "startup": "java -Xmx2048M -jar server.jar --port 25565" Good: "startup": "java -Xms128M -XX:MaxRAMPercentage=95.0 -jar {{SERVER_JARFILE}}"

Wrong Variable Format in startup vs config.files

In startup command: {{VARIABLE_NAME}} In config.files parser: {{server.build.env.VARIABLE_NAME}}

Mixing these up means your variables simply won't work!

Wrong field_type Value

Bad: "field_type": "number" or "field_type": "password" or "field_type": "boolean" Good: "field_type": "text" — it is always "text", no exceptions. Use rules to express the data type.

Missing user_viewable / user_editable

Bad:

{
  "name": "Server Port",
  "env_variable": "SERVER_PORT",
  "default_value": "25565",
  "rules": "required|numeric|between:1024,65535",
  "field_type": "text"
}

Good:

{
  "name": "Server Port",
  "description": "The port your server listens on",
  "env_variable": "SERVER_PORT",
  "default_value": "25565",
  "user_viewable": true,
  "user_editable": true,
  "rules": "required|numeric|between:1024,65535",
  "field_type": "text"
}

Typos in Variable Names

Bad: "env_variable": "SERVER_NAME" but using {{SERVER_NAEM}} in startup Good: Spell consistently and double-check every reference!

No Description

Bad: "description": "" Good: "description": "Your Discord bot token from the Developer Portal"

Invalid JSON

Test your JSON with a JSON validator before submitting!

Wrong Parser Type

Bad: "parser": "json" for a YAML file Good: "parser": "yaml" for YAML files

Wrong Install Path

Bad: Writing files to /home/container inside the installation script Good: Installation script always writes to /mnt/server

Not Testing

Bad: Creating an egg and never testing it Good: Test thoroughly before sharing — at least one full fresh install!

No Error Handling

Bad: Installation script that fails silently Good: Script checks for errors and reports them clearly

🎯 Before You Share

Final checklist before releasing your egg:

  • Metadata is complete and accurate
  • All variables include every required field (name, description, env_variable, default_value, user_viewable, user_editable, rules, field_type)
  • Every field_type is "text"
  • Installation script writes to /mnt/server and works from scratch
  • Startup command works properly and uses {{VARIABLE_NAME}} syntax
  • Configuration files are managed correctly using {{server.build.env.VARIABLE_NAME}}
  • Tested on fresh installation
  • Tested changing each variable
  • Tested edge cases (long names, special chars)
  • No hardcoded values anywhere
  • JSON is valid (use an online JSON validator!)
  • No typos in the file
  • Docker runtime image uses ghcr.io/ptero-eggs/yolks:* registry
  • Installer container uses ghcr.io/ptero-eggs/installers:debian or :alpine
  • All file paths use forward slashes (/)
  • No secrets or real tokens in default values
  • Compared with similar working eggs for reference
  • Ready to share! 🎉

📊 Quality Scoring

Rate your egg on these criteria:

Criteria Points Your Score
Complete metadata 10 ___
Well-documented variables (all fields present) 15 ___
Working installation 15 ___
Proper startup detection 10 ___
Config file management 15 ___
Error handling in install script 10 ___
Correct registries and paths 10 ___
Testing 10 ___
Total 95 ___

Score: 80+ = Great egg, 70+ = Good egg, below 70 = Needs work

🔄 Egg Creation Workflow

  1. Plan — Decide what you're creating and what variables are needed
  2. Research — Look at similar existing eggs for reference
  3. Structure — Create the basic egg JSON structure
  4. Variables — Define all user-customizable settings with every required field
  5. Startup — Write and test the startup command
  6. Installation — Write the installation script (files go to /mnt/server)
  7. Configuration — Set up file management with parsers
  8. Documentation — Write a README explaining usage
  9. Testing — Thoroughly test everything from scratch
  10. Review — Check against this checklist
  11. Share — Release to the community!

🎓 Learning Resources

💡 Pro Tips

  1. Start simple — Create a basic egg first, add features later
  2. Reference real eggs — Check Wings Variables Extracted for patterns
  3. Test often — Don't wait until the end to test
  4. Get feedback — Have others review your egg
  5. Keep improving — Version your eggs and improve over time
  6. Document well — Good descriptions help users understand what to fill in
  7. Be consistent — Follow naming patterns and conventions (SNAKE_CASE for env_variable)
  8. Validate JSON — Use an online JSON validator every time you edit the file
  9. Test edge cases — Not just the happy path
  10. Read error messages — They tell you exactly what's wrong!

🎉 You're Ready!

If you've completed this checklist, your egg is ready to share with the community!

Remember:

  • Eggs are a single .json file — no folders, no separate scripts
  • field_type is always "text" — use rules to express the data type
  • Install path = /mnt/server, runtime path = /home/container
  • Start simple, test thoroughly, help your users, keep improving

Good luck! 🥚🚀


Have questions? Check the complete documentation.

Ready to create? Start with Egg Basics.