In case you missed it, the JSSImporter processor is deprecated, and will cease to function when Jamf remove basic authentication from the Classic API endpoints, which they have announced will happen sometime between August and December 2022.

The JamfUploader project is my replacement of JSSImporter, for Jamf Pro customers that want to continue to benefit from the power of AutoPkg for obtaining deployable packages for thousands of third party applications and other software.

JamfUploader-based (.jamf) recipes are modular in design (see my original blog post, JamfUploader - new AutoPkg processors for importing packages to Jamf Pro). The design is significantly different to JSSImporter-based (.jss) recipes, so new recipes need to be written.

Is there an easy way to convert a .jss recipe to a .jamf recipe?

JamfUploader is designed to be more flexible than JSSImporter, so a straight conversion may well not be the best course of action. For example, if you’re using Patch Management, or creating multiple policies, JSSImporter recipes were not well designed for this, and you can benefit from the new opportunities available with JamfUploader.

However, if your policy and smart group design is compatible with the “standard” design devised for .jss recipes, you may be contemplating having to write a bunch of .jamf recipe that do exactly the same thing as those existing “standard” .jss recipes that are currently available in the jss-recipes and various other repos, notably rtrouton-recipes.

To help achieve this, I’ve developed a novel idea - a new AutoPkg processor that reads from a .jss recipe while running it, and writes a new .jamf recipe.

Say hello to JamfRecipeMaker.

Huh? An AutoPkg processor that reads one recipe and writes another?

Exactly. Sounds weird, but when you run an AutoPkg recipe, all the relevant variable values are written as environment variables, so it’s all available for doing whatever you want. In a “standard” .jss recipe, the only values we really need to obtain are:

  • ParentRecipe
  • NAME

We just need to write these to a file in the correct structure of a .jamf recipe. This is pretty much what Elliot Jordan’s excellent Recipe Robot app is doing when generating a .jss or indeed .munki recipe, after all.

How does JamfRecipeMaker work?!

We can use JamfRecipeMaker as a pre-processor (or post-processor if you like) when running a .jss recipe. There are 2 main options:

(1) Create a recipe that just uploads a package and nothing else. This is functionally equivalent to .jss-upload recipes as was described in Daz Wallace’s 2019 blog post Using Autopkg for package Uploads to Jamf Cloud only. These types of .jamf recipe do not need any information from a .jss recipe (we only need ParentRecipe and NAME), so can be run directly from a .pkg recipe.

autopkg run Flux.pkg --pre

(2) Create a recipe that uploads a package, smart group and policy. This is functionally equivalent to standard .jss recipes.

    autopkg run Flux.jss --key make_policy=True --post

The advantage of adding the processor as a pre-processor is that if the .jss recipe stops mid-run, the .jamf recipe is already generated.

Both these options make recipes in YAML format by default. You can instead output a PLIST recipe by adding --key format=plist to your command.

If you wish to ensure that the categories associated with the package and policy are created if they do not yet exist, add --key make_categories=True.

The make_categories, make_policy and format keys can instead be added to your AutoPkg prefs:

defaults write ~/Library/Preferences/com.github.autopkg.plist make_policy -bool YES
defaults write ~/Library/Preferences/com.github.autopkg.plist make_categories -bool YES
defaults write ~/Library/Preferences/com.github.autopkg.plist format plist

You’ll probably want to supply your own Recipe Identifier prefix too, either using a --key or by adding to your prefs:

defaults write ~/Library/Preferences/com.github.autopkg.plist RECIPE_IDENTIFIER_PREFIX com.acme.autopkg-recipes

And you can specify the output path for the jamf recipes. The default is whatever directory you run the command from (.):

defaults write ~/Library/Preferences/com.github.autopkg.plist RECIPE_OUTPUT_PATH /path/to/my/recipe-repo/Jamf_Recipes

For full documentation, incluiding more options for feeding in variables, see the JamfRecipeMaker wiki.

Do I have to install anything special to use JamfRecipeMaker?

No, so long as you have added the grahampugh-recipes repo, you should be good to go.

There are some additional requirements, specifically the ruamel.yaml python module. That’s because I yanked most of the code from my existing plist-yaml-plist project for converting PLIST to YAML and vice versa. The processor will attempt to install ruamel.yaml into the AutoPkg python library if missing, so you shouldn’t have to do anything in advance to make this work. But let me know if you encounter any problems with that.

One more thing! I’ve already used JamfRecipeMaker to make around 100 .jamf and -pkg-upload.jamf recipes

Since it’s possible to run this against a recipe list, I decided to convert all the working recipes in the jss-recipes repo to .jamf and -pkg-upload.jamf recipes. These are now in the grahampugh-recipes repo (see the Jamf_Recipes and Jamf_Package_Upload_Only folders), and they are searchable via the autopkg search command.


Please note that I don’t use these recipes, as my organisation’s requirements are not the same as that “standard” design. So, these generated recipes have not been tested. They are simply there to try and help adoption of JamfUploader sooner.

The -pkg-upload.jamf recipes are all likely to work, because all the .jss recipes did complete when I was generating them, and all the .jamf recipes should upload the packages. However, JamfRecipeMaker does not currently look for scripts, extension attributes or other customisations away from the “standard” basic .jss recipe design, and I have not edited the automatically-generated recipes. So, treat the recipes as a basis for developing your own recipes to suit your own particular workflows. If you decide to use these recipes in production and discover the recipes that aren’t working as they should, I would welcome PRs that add the scripts, extension attributes or whatever else is required to make them fully functional.


I hope the JamfRecipeMaker processor and the auto-generated .jamf recipes will make the migration from JSSImporter to JamfUploader quicker and easier for some organisations.

I am aware that AutoPkgr has still not been updated to include support for YAML-based recipes, but is still widely used by members of the Mac Admins community. I could easily generate all the .jamf recipes again in PLIST format with a different recipe identifier, but I’m concerned about all the duplicate entries in the AutoPkg search results that would occur as a result.

I would consider removing the YAML recipes and re-creating them as PLIST recipes if there is enough demand. Let me know in the MacAdmins Slack Team #jamf-upload or #autopkg channels if this would be useful.