PHPackages                             proximify/packman - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [DevOps &amp; Deployment](/categories/devops)
4. /
5. proximify/packman

ActiveComposer-plugin[DevOps &amp; Deployment](/categories/devops)

proximify/packman
=================

A Composer Satis plugin for managing private packages using a local packaging server.

1.1.2(5y ago)128MITPHPPHP &gt;=7.2.0CI failing

Since Nov 14Pushed 5y ago1 watchersCompare

[ Source](https://github.com/Proximify/packman)[ Packagist](https://packagist.org/packages/proximify/packman)[ RSS](/packages/proximify-packman/feed)WikiDiscussions master Synced 1w ago

READMEChangelog (6)Dependencies (2)Versions (11)Used By (0)

 [![proximify packman plugin icon](docs/assets/proximify_packman.svg)](docs/assets/proximify_packman.svg)

Packman
=======

[](#packman)

This Composer plugin creates a package manager and serves private packages to Composer from a local web server. By default, it creates one package manager per project within a `packman` folder. A local web server is started and stopped automatically when needed by a composer task (usually `http://localhost:8081`). Packman assumes that all private packages have the same vendor name and that their source is hosted at a common location (e.g. `https://github.com/CompanyName/...`).

Terminology
-----------

[](#terminology)

In Composer terminology, a **repository** is a set of packages, and a **package** is simply a commit in a repository. A commit can be identified in relative terms by its tag (it it has one), and optionally, by brach name. The `composer.lock` identifies a package by its commit hash whereas the `composer.json` declares [version constraint](https://getcomposer.org/doc/articles/versions.md#versions-and-constraints) for all required packages. For example, in plain English, version constraints read as "most recent commit in the develop branch" or "package with version 1.0 or higher".

A **private repository** is a set of **private packages**. Packages can be required by other packages in relative terms based on their [semantic version](#semantic-versioning). That is, instead of specifying a commit hash, one can request the newest package that matches a version pattern, such as `1.1.*`.

After running composer `install`, `update` or `require`, the resulting `require` pattern of each package is **locked** to the specific **commit hash** that **satisfies** the required [version constraint](https://getcomposer.org/doc/articles/versions.md#versions-and-constraints).

Composer has a special syntax to declare constraints based on branch names. The `dev-NAME` prefix tells composer that you want the branch named `NAME`. In that case, Composer assumes that you want a clone of the repo in your vendor folder instead of just the files in the repo. The main difference is that you can go into the repo within the vendor folder, make changes and commit directly from there. That is convenient when developing interdependent modules. You can modify the dependant and **skip** the `composer update DEPENDANT` step since you already have the latest version (in fact, you had it before its remote repo).

> "If you wanted to check out the my-feature branch, you would specify dev-my-feature as the version constraint in your require clause. This would result in Composer cloning the my-library repository into my vendor directory and checking out the my-feature branch."

In contrast, for tag based constraints, Composer copies the needed files without cloning the repo. This behavior can be modified with the --prefer-source and --prefer-dist options.

Composer limits which tags are considered **valid** based on the value of "minimum-stability" in composer.json, which defaults to "stable". To work with development-level packages (including tags suffixed with -dev, -alpha, etc), set the minimum stability to `@dev`. Alternatively, **stability flags** are version constraints in the form `"constraint@LEVEL"`, where `constraint` can be empty and `LEVEL` is the stability level. The flag tells Composer that a given package can be installed in a different stability than the `minimum-stability` setting. For example,

```
{
    "require": {
        "monolog/monolog": "1.0.*@beta",
        "acme/foo": "@dev"
    }
}
```

**Version constraints** can be defined as ranges `1.0 - 2.0`, `>=1.0.0 =1.2 =1.2.3  Packman will activate for all composer projects and see if they depend on private packages. If they don't, it won't do anything, so you won't get a `packman` folder in projects that don't need it.

### Method 2: Per-project install

[](#method-2-per-project-install)

Add the plugin to the development dependencies of your project

```
$ composer require proximify/packman --dev
```

The method works well on new projects because Packman can be installed before the private packages. However, when performing a `composer install` on an existing project with private packages, Packman won't yet be available to plugin into Composer and manage them. A possible, clunky solution for such cases is to remove the private dependencies from the project, install Packman, and then put them back. Since that's not super fun, we recommend installing Packman globally.

Using Cloned and Symlink repositories
-------------------------------------

[](#using-cloned-and-symlink-repositories)

When developing multiple interdependent components at the same time, it is better to work with the dependant **repositories** directly instead of using copies of their package files fetched by satisfying version constraints. There are two mains ways to do that. One is to require a package with a branch constraint instead of a tag constraint. For example,

```
$ composer require proximify/bibutils:dev-master
```

requires the branch "master" (the `dev-` prefix means "branch name"). When requesting a package by branch name, Composer clones the repo within the appropriate place in the `vendor` folder. Having a cloned repo instead just files means that you can make changes to it and then commit from its location in the vendor folder. It is weird, but it does the job.

An alternative to that approach is to use [symlink repositories](https://getcomposer.org/doc/05-repositories.md#path). Similarly to the cloned repo approach, the dependant packages won't need to be updated via composer every time they are locally changed by you. You can modify your local copy of the repo and the change is "applied" to the copy of the package within the vendor folder of another project.

Conceptually, the symlink approach and the cloned repo approach are identical. The only difference is that the cloned repo approach keeps an independent clone within the vendor folder, so if you also have the repo somewhere else, you have to remember to pull the latest changes in the clone that was not modified directly. With symlinks, you avoid that step.

Packman can add symlink repositories to composer automatically when a Composer command is run. To enable that feature, the `symlinkDir` option has to be set to an existing directory. When `symlinkDir` is defined, any repository name listed under `symlinks` will be designated as a path-type repository and symlinked, even if publicly available from Packagist.

Packman adds the **symlink repositories** to the active composer object automatically so there is no need to manually add them to the `repositories` section of a `composer.json`.

```
// composer.json
{
    "extra": {
        "packman": {
            "symlinkDir": "../",
            "symlinks": ["repo-name1", "repo-name2"]
        }
    }
}
```

**Note:** If the `symlinkDir` value is set, the committed `composer.json`, it should be given as a relative path (either `../` or `~/`). By doing that, other members of your team will be able to have a similar configuration for them. If you don't expect other team members to also use symlink repositories, you should set the `symlinkDir` value in the local `packman/packman.json` file, which is in `.gitignore` by default. Alternatively, you can set the its value in the global `~/.composer/composer.json`.

> Make sure that the composer.json files at "../repo-name1" and "../repo-name2" set "name" to "my-org/repo-name1" and "my-org/repo-name2", respectively. In other words, the name of a package is defined by its composer file and not by the path to its repo.

### Manual symlink repositories

[](#manual-symlink-repositories)

If you prefer defining your symlink repositories explicitly, it's a good idea to define them in the **global** composer settings. In that way, you don't have to remember to remove the repository specs from each local `composer.json` that needs it.

```
// Example global configuration of a symlink repository
// ~/.composer/composer.json
{
    "require": {
        "my-org/my-repo": "@dev"
    },
    "repositories": [
        {
            "type": "path",
            "url": "../my-repo",
            "options": {
                "symlink": true
            }
        }
    ]
}
```

The variables here are: `my-org`, `my-repo`, and the value of `url`. Everything else stays as shown.

> Use a relative path for the "url" that works for all the members of your dev team. You can either start from your home directory with `~/` or you can make it relative to the root project with `../`. The `~/` is convenient for packages installed globally. The `../` allows for more freedom as long as the package is not installed globally or that the relative path also works from the global `.composer` folder.

### Combining Packman and Symlink Repositories

[](#combining-packman-and-symlink-repositories)

It is fine and normal to have both symlink repositories and private once managed with [![packman icon](docs/assets/proximify_packman.svg)](docs/assets/proximify_packman.svg). The symlink repositories will have higher precedence than the private ones.

Once the Packman plugin is installed to fetch remote private packages, and the global and/or local `composer.json` is configured for any additional local symlink repositories, you can run

```
composer require my-org/my-repo:dev-master
```

to get the package defined as the latest development commit of the master branch of the given repository.

### Deployment to Prod

[](#deployment-to-prod)

It's not a good idea to use symlink repositories to deploy to a production machine. The symlink repositories are only meant for local development. In contrast, Packman can be used to deploy to a production server (e.g. as a zip bundle). But, if the intent is to fetch the packages on the production server, then the default Packman solution of hosting private packages on `localhost` won't work if that URL is not authenticated in some way. In other words, **Packman is for local machines only**. If used on a server, the Packman URL (`localUrl`) should only be accessible **only** from the local machine.

Options
-------

[](#options)

The assumption that private packages have the same vendor name than that of the root project might not be correct. The vendor name to use for private packages can be set via a custom parameter.

Custom parameter values can be set in three different places, in the `extra` property of the root project's `composer.json`, in the `extra` property of the global `composer.json` (usually under `~/.composer`), and in the `packman.json` (usually under `./packman`). The three sources are merged, with the packman file having priority over the local composer, and the global composer options having the least priority.

are set in the `composer.json` under the `extra` property. For example,

```
// composer.json
{
    "name": "my-vendor/my-composer-project",
    "extra": {
        "packman": {
            "vendor": "alt-my-vendor",
            "localUrl": "http://localhost:8081",
            "remoteUrl": "https://github.com"
        }
    }
}
```

If the protocol of the **localUrl** is http instead of https, **packman** will set the `secure-http` to `false` (see [secure-http](https://getcomposer.org/doc/06-config.md#secure-http)). Othewrise, Composer will refuse to contact a URL like `http://localhost:8081`.

### Parameters

[](#parameters)

The paremeters are set in the global and/or local composer.json files under the keys `extra: {packman: { ... }}`.

ParameterDefault valueDescriptionvendor`{ROOT-VENDOR}`The vendor name of the private packages to manage.remoteUrl`https://github.com/{ROOT-VENDOR}`Base URL of the repository hosting servers where the private repositories are located.localUrl`http://localhost:8081`The URL to be used for the local server of Composer packages.packmanDir`packman`The folder where to used by Packman to store repositories and the `packman.json` configuration file. It can be local to each project (default), or shared by multiple projects.symlinkDirThe folder to used for symlinked repositories.symlinksAn array of repository names to symlink.Commands
--------

[](#commands)

[![packman icon](docs/assets/proximify_packman.svg)](docs/assets/proximify_packman.svg) runs automatically when composer runs, and, in general, it does the right thing at the right time. However, it is also possible to run commands on demand using `composer COMMAND`.

 ParameterDescriptionpackman-buildPerform an update of all registered packages.packman-resetReset the entire package store.packman-startBuild private packages and start the local web server to server them to composer.packman-stopStop the local web server that servers the packages to composer.packman-linkAdds the given folder names to the `packman.json` under the symlinks key. Note that tt does not add packages but just local repo folders. Packages requirements have to be added with `composer require`. It only adds the instructions to symlink to repository folders where some required packages can be found.packman-unlinkRemove symlinks from the `packman.json` file.Semantic versioning
-------------------

[](#semantic-versioning)

By tagging a commit, one can attach a semantic version ([semver](https://semver.org/)) to a commit in order to make it referentiable in relative terms. For example, package "vendor/repo:1.2.0-beta" is the commit in the master brach that has the tag '1.2.0-beta'.

Version suffix labels of the form "-label" provide an additional way to communicate information about the state and intent of a particular commit. The meaning of lables is rank order as: `dev`, `alpha`, `beta`, `rc`, and they can have a numeric suffix too, such as `beta1` or `rc2`. A no-label version number, `n.n.n`, is a higher version than the same number with a label, `n.n.n-label`, for any label.

An untagged commit represents a package with an unknown version number that exists within a range of known version numbers. It's still possible to refer to an untagged commit. For example, one can request the last commit before a tagged commit.

When asking for a "vendor/repo:dev-master" **package**, one is asking for the latest commit in the `master` branch of the "vendor/repo" repository with label `-dev` or higher. For example, a `-alpha` labelled version number would meet that condition.

About Satis
-----------

[](#about-satis)

This plugin uses the [Satis](https://composer.github.io/satis/) repository generator (see using satis).

---

Contributing
------------

[](#contributing)

This project welcomes contributions and suggestions.

License
-------

[](#license)

Copyright (c) Proximify Inc. All rights reserved.

Licensed under the [MIT](https://opensource.org/licenses/MIT) license.

**Software component** is made by [Proximify](https://proximify.com). We invite the community to participate.

###  Health Score

25

—

LowBetter than 37% of packages

Maintenance20

Infrequent updates — may be unmaintained

Popularity9

Limited adoption so far

Community7

Small or concentrated contributor base

Maturity55

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~2 days

Total

10

Last Release

1993d ago

Major Versions

0.0.1 → 1.0.0-beta2020-11-18

### Community

Maintainers

![](https://avatars.githubusercontent.com/u/1322822?v=4)[Proximify](/maintainers/proximify)[@Proximify](https://github.com/Proximify)

---

Top Contributors

[![macrini](https://avatars.githubusercontent.com/u/1253463?v=4)](https://github.com/macrini "macrini (55 commits)")

### Embed Badge

![Health badge](/badges/proximify-packman/health.svg)

```
[![Health](https://phpackages.com/badges/proximify-packman/health.svg)](https://phpackages.com/packages/proximify-packman)
```

###  Alternatives

[johnpbloch/wordpress-core-installer

A custom installer to handle deploying WordPress with composer

22110.8M47](/packages/johnpbloch-wordpress-core-installer)[civicrm/composer-compile-plugin

Define a 'compile' event for all packages in the dependency-graph

12488.2k15](/packages/civicrm-composer-compile-plugin)[enumag/no-thanks

Prevents symfony/flex from printing thanks reminder.

3315.6k](/packages/enumag-no-thanks)[inpsyde/vip-composer-plugin

A Composer plugin to ease deployment to wordpress.com VIP servers alongside Composer-based development.

1258.2k](/packages/inpsyde-vip-composer-plugin)[stephank/composer-plugin-nixify

Composer plugin to help with Nix packaging

1710.5k](/packages/stephank-composer-plugin-nixify)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
