Skip to content

Layers

A layer is a directory that contributes project setup to a ParaSpace workspace. It may hold hooks/, skel/, commands/, and a configure script, and every part is optional.

Its hooks run in stack order, against the contract in Hooks. Its seed files sit in skel/, where its own hooks reach them at $PARA_LAYER_DIR/skel, and anything in commands/ becomes a project command.

On every para up, the resolved layers are pushed into the workspace fresh at ~/.paraspace/stack/<layer name>. Symlinks are followed on the push, so a package installed with npm link or bun link lands as real files in the guest. See Hooks for the guest layout.

The stack file

.paraspace/stack is the project's layer list. It contains one directory path per line:

text
node_modules/paraspace/layers/base/void
node_modules/paraspace/layers/docker
node_modules/paraspace/layers/git
.paraspace/layers/project

Inspect or edit it directly:

sh
cat .paraspace/stack
${EDITOR:-vi} .paraspace/stack

The list composes from top to bottom, and each line resolves against the project root. Blank lines and # comments are skipped, and surrounding whitespace and trailing slashes are trimmed, so you can document a non-obvious entry in place. Every path in the list has to be a directory that already exists.

The paths are literal. Nothing searches for layer names, resolves packages at runtime, or normalizes equivalent paths, so in a hoisted monorepo write the path that is true for this project, such as ../../node_modules/....

Check the resolved stack order with:

sh
para doctor

If a layer under node_modules/ is missing after a fresh clone, install the project's dependencies:

sh
npm install

Each layer also needs a unique layer name. Bundled and plugin layers use their catalog names, project-owned layers keep their path beneath .paraspace/layers/, and other paths use their final directory name. If two entries share a name, rename one directory or copy one under .paraspace/layers/ with a different name.

After changing the list by hand, run:

sh
para init

That rechecks the list and reruns each layer's configure script, without recreating what is already there.

Start a project

sh
npm install --save-dev paraspace
para init

Add ParaSpace to a project covers the rest of the setup. A bare para init refuses when node_modules/paraspace is absent, so install it first, or name a layer or path when initializing. Naming layers on that first run skips the default base, so the stack holds exactly the list you gave.

Add a layer

Add bundled layers by name:

sh
para add docker git

Add an existing directory by path:

sh
para add ../shared/paraspace-layer

para add expands accepted names into explicit paths in .paraspace/stack. Bundled names resolve beneath para's layers/ directory. Installed plugin layers use vendor/name entries. Other arguments are paths, tried as written and then beneath node_modules/.

If a name matches more than one candidate, such as both a directory and a plugin layer, para add refuses and names each candidate. Use the full path for the layer you mean.

See the catalog of bundled, plugin, and project-owned layers, with the entries already in your stack marked:

sh
para add --list

Adding a layer already present leaves the layer list unchanged. New layers are inserted before project-owned layers, which remain last so their files and verbs take precedence.

Create a project layer

Create a new layer owned by this project and add it to the layer list:

sh
para add --new local-tools

You get .paraspace/layers/local-tools/ with image-build, provision, and boot hook stubs, placed before the project layer. Fill in the hooks, seed files, commands, or a configure script the layer needs.

Base layers

By convention, the first layer is a base, and it establishes the image, bootstrap, and workspace user. A base is any layer with a base/ component in its stack path. It composes like any other layer, but para doctor warns when the list has no base or more than one.

Customize a packaged layer

Copy a packaged layer into the project, replace its packaged path in the stack, and apply the updated configuration:

sh
cp -R node_modules/paraspace/layers/docker .paraspace/layers/docker
${EDITOR:-vi} .paraspace/stack
para init

The copy is now project-owned. npm updates do not modify it.

Configure layers

para init and para add run each layer's optional configure script in stack order. These scripts run on the host from the project root with your privileges, so review third-party layers before adding them.

Every PARA_* variable is exported to a configure script, and PARA_LAYER_DIR identifies that script's layer directory. A script can propose env values through the maybe_write_env helper from $PARA_HELPERS:

sh
maybe_write_env PARA_ROUTES "3000"

Existing declarations in .paraspace/env take precedence; see The env file for its rules. The bundled docker layer's configure script derives PARA_ROUTES and PARA_PREPULL_IMAGES from a resolved Compose model.

A failing configure script stops the chain with that layer's exit status. Fix the layer, then rerun para add to converge. Configure scripts never run during para up, so starting a workspace never rewrites files you committed.

Released under the MIT License.