Tooling for managing & packaging Arma 3 scenarios (old/not really maintained)
Actually restoring support for windows' command prompt


browse log




Artifex is an experiment and a build tool for ArmA missions and mods. It is intended to be cross platform and is in the very early stages of development.

Overall, reducing tedium is the main objective of this project. That is accomplished by way of automation, making missions and mods more modular, and alliteration.


Python, probably requires version 3.4 or above.

makepbo, support for other pbo packagers may be added later.

System Setup

  1. Ensure the environment variable ARMALAND is set to the root ArmA installation directory. It's recommended you set this through Windows' "Environment Variables" dialog thing so that you don't have to set it each time you open a command prompt.

Project Setup

Most of this is probably wrong and I'm too lazy to update it. The gist is that you add the bin directory to your path and there is no need to run setenv.

  1. Let P be the directory of the project you wish to use this for. Clone Artifex to a directory underneath P, that we will refer to as A, such that A/.. == P.

  2. Copy A/artifex.ini.sample to P/artifex.ini; tweak it to your liking. Alternatively, if you've done the step below under "Usage" and added art to your PATH you can use the art config command to set the name and map attributes under the project.

     > art config project name OperationBananas
     INFO:artifex.venue:Writing config file back to artifex.ini
     INFO:artifex.main:Task "config" complete
     > art config project map Altis
     INFO:artifex.venue:Writing config file back to artifex.ini
     INFO:artifex.main:Task "config" complete


  1. In a command prompt, in which the working directory is P, run A/setenv.bat. This initializes the prompt to correctly use artifex. You should then be able to invoke artifex by typing art which should use the project configuration to produce a pbo file which it will place in the MPMissions directory under ARMALAND.

Extended Usage

Configuration Files

In addition to looking for a artifex.ini file under the project directory, P, Artifex loads configuration files in two other places.

The first is at P/artifex.local.ini, this file is meant to be ignored by the version control in P so that it can serve an easy way for users to apply customizations based on their particular machine and the particular clone. The existence of this file is optional. Artifex will not steal your babies if it is missing.

The other configuration file is at ~/artifex.ini, which expands to %USERPROFILE%\artifex.ini on windows. It works similar to the local configuration file. It's purpose is for storing configuration that is meant to be used across all projects on a user's machine. The existence of this file is optional. Artifex will not steal your babies if it is missing.


This is going to change, so close your eyes and ignore it.

Artifex can be extended with python modules. After loading the configuration from all three files artifex will check the ext section and, for each option found in that section, attempt to import a Python module with that name.

Prior to importing, the Python module search path is modified to include ~/.artifex, ~/_artifex on Windows if it exists, and P/.artifex.

Modules must provide an action attribute, to which a callable taking an artifex.climate.AbstractContext, configparser.ConfigParser, and argparse.Namespace is assigned.

If the setup_parser attribute exists on the module, it will be called and passed an argparse.ArgumentParser. The module can then call add_argument as a way of describing what arguments the action takes.

In the future, not all extensions will need to provide an action. And extensions that do provide an action will not be limited to providing only one.


This is going to change, so close your eyes and ignore it.

Example P/artifex.local.ini:


Example ~/artifex.ini:

runds =

Example ~/.artifex/

import os.path
import artifex.beget

def action(ctx, cfg, opts):
    armaland = ctx.require('ARMALAND')
    mod_list = next(zip(*cfg.items('mods')))
    p = artifex.beget.spawn(
            os.path.join(armaland, 'arma3server.exe'),
            '-mod=' + ';'.join(mod_list),

[]( vim: tw=79 spell )