Installation
Install, update, pin and uninstall theway.
Requirements
~/.local/binon yourPATH, or another install folder that is (see Other locations). The commands call the CLI as plaintheway, so they fail withtheway: command not foundwhen its folder is not onPATH. On macOS it is not there by default: addexport PATH="$HOME/.local/bin:$PATH"to your shell profile, then start Claude Code from a new shell.- Node.js 22.12 or later.
- macOS or Linux.
- Claude Code.
Install and update
npx --yes @pixelfactoryio/theway@latest installEvery run fetches the latest release from npm, so running the command again updates theway. When it finishes, start a new Claude Code session or run /reload-plugins.
On a first install from a terminal, install asks two questions before it writes anything:
- Where should theway keep its data? Asked only when theway was never installed (no
THEWAY_HOME, no pointer file and no~/.theway/config.yaml). Press Enter for~/.theway, or type an absolute path or one starting with~/. A path install would refuse (see Other locations) is rejected and asked again. - Enable opt-in standards. Asked only when the chosen data home has no
config.yaml. Pick any ofcore_principles,sre,web_developmentandqualitywith Space, or none, then press Enter.
Ctrl-C at either question exits 1 with theway: install cancelled; nothing was changed.
Two options give the same choices without a question, and win over the terminal:
--home <path>: the data home, an absolute path or one starting with~/. It takes precedence over the pointer file. WhenTHEWAY_HOMEis set to another path, install exits 1 and changes nothing.--standards <keys>: a comma-separated list of opt-in keys, such assre,quality, ornone. It applies only to a first install: when the data home already has aconfig.yaml, install exits 1 and changes nothing, so setstandards.<key>.enabledthere instead. An unknown key, ornonecombined with a key, also exits 1.
npx --yes @pixelfactoryio/theway@latest install --home ~/work/theway --standards sre,qualityWithout a terminal, as in Claude Code's ! prefix, install asks nothing: pass the options instead. In a Claude Code session:
! npx --yes @pixelfactoryio/theway@latest install --home <path> --standards <keys>A first install with no terminal and no --standards leaves the four opt-in standards off and prints Opt-in standards are off (core_principles, sre, web_development, quality): set standards.<key>.enabled: true in <home>/config.yaml to enable one.
When the install folder is not on your PATH, install still finishes and exits 0, and prints the line to add:
Add /home/you/.local/bin to your PATH, e.g.: export PATH="/home/you/.local/bin:$PATH"Pin to a release
To install a specific release, add its version:
npx --yes @pixelfactoryio/theway@X.Y.Z installThe versions are listed on npm.
Uninstall
npx --yes @pixelfactoryio/theway@latest uninstallUninstall removes ~/.claude/skills/theway, the theway binary when it is the one install wrote, the pointer file and the permission rules: those of THEWAY_HOME, of the home the pointer names and of ~/.theway, and the rules of 0.2.0. The data home (~/.theway, or your custom home) is kept, with your changes and your config.
What install writes
-
~/.claude/skills/theway: the plugin, with its commands and therun-pipelineworkflow that/theway:workflowcalls. Claude Code loads it astheway@skills-dir. Each install replaces this folder. -
~/.local/bin/theway: the CLI the commands call, a single executable file run by thenodeon yourPATH. Install replaces a theway binary there, but not another program calledtheway: it then stops, changes nothing, and asks you to remove it or setTHEWAY_INSTALL_DIR. -
The data home,
~/.thewayby default:config.yaml: the configuration. A new one is the shipped configuration withenabled: trueunder each opt-in standard you picked at the prompt or with--standards, and every other line as shipped. An existingconfig.yamlis kept.config.default.yaml: the shipped configuration, written on every install.standards/,templates/,workflows/andprompts/: the standards, templates, workflows and prompts the commands read. Install updates the files you have not edited. A file you edited is kept, and the new shipped version is written next to it as<name>.default.mdor<name>.default.yaml..shipped.jsonrecords what install last shipped.workflows/andprompts/also hold your own workflows and prompts, and follow the rules ofstandards/below: your file with a newly shipped name is kept, and a file theway stops shipping is removed when you have not edited it. An editedtheway.workflow/v1workflow is kept, with the new one next to it as<name>.default.yaml, and install says so (workflows/<name>.yaml is a theway.workflow/v1 file, which theway no longer reads: rewrite it from workflows/<name>.default.yaml); rewrite yours astheway.workflow/v1beta(see Moving from v1). An edited prompt with no header, whose shipped version has one, is kept the same way and getsprompts/<name>.md has no header, so the workflows that use it fail: merge your edits into prompts/<name>.default.md and replace it: until you do, it hides the shipped prompt of that name.- theway no longer reads
steps/nor shipsschemas/. Install removes an unedited shipped step file or schema (Removed steps/<name>.yaml: theway no longer ships it), keeps an edited one with a message (Kept your edited steps/<name>.yaml: theway no longer reads steps/; write its steps in a workflow file,Kept your edited schemas/<name>.json: theway no longer ships it), keeps any other step file of yours (Kept steps/<name>.yaml: theway no longer reads steps/; write its steps in a workflow file), removes their.defaultcopies, and removes each folder once it is empty. A project'sprojects/<key>/steps/is never emptied: each file there getsKept projects/<key>/steps/<name>.yaml: theway no longer reads steps/; write its steps in a workflow file. - A kept
config.yamlwith aworkflow:key printsYour config.yaml still has workflow: theway no longer reads workflow.defaults; set a value in the workflow file or in the prompt's header, and remove the key, and one withengineering:printsYour config.yaml still has engineering: theway ignores it; remove it. Install never edits it. - The review lenses of earlier versions are prompts now: install removes an unedited shipped lens from the old lenses folder, keeps an edited one or one of yours with a message to move it to
prompts/, and removes the folder once it is empty. standards/also holds your global user standards. When theway starts shipping a name you already use there, install keeps your file, writes its version as<name>.default.md, leaves the name out of.shipped.jsonso the file stays yours, and printsKept your standards/<name>: theway now ships a file with that name (its version: standards/<base>.default.md)on every install while the clash lasts. When you have no.shipped.json, a differing file with a shipped name is treated as an edited shipped file instead.- A standard theway stops shipping is removed when you have not edited it (
Removed standards/<name>: theway no longer ships it) and kept as one of your standards when you have (Kept your edited standards/<name>: theway no longer ships it, so it is now one of your standards). Install also removes astandards/<name>.default.mdwhose<name>.mdit no longer ships. - The Authority rules are in
standards/authority.md, whichtheway authorityprints. When install keeps an editedstandards/interaction.mdthat still has a## Authorityline, it addsstandards/interaction.md still has an Authority section: theway now reads standards/authority.md; move your edits there. Astandards/authority.mdof your own, one.shipped.jsondoes not list, stays a user standard: install printsKept your standards/authority.md: theway now ships a file with that name (its version: standards/authority.default.md), andtheway authorityprints the shippedauthority.default.md. On a home with no.shipped.json, an existingstandards/authority.mdis taken as yours this way, not as an edited shipped file: theway shipped it long after it first wrote.shipped.json. - When install keeps an edited file of
standards/orprompts/whose text still namestasks.md, it adds<rel> still names tasks.md: theway now keeps tasks in change.yaml; compare it with <dir>/<name>.default.md. - A template theway no longer ships is left in
templates/untouched. A differing template that.shipped.jsondoes not list is backed up to<name>.md.bakand replaced. - The engineering standards and spec templates of earlier versions are prompts now (
prompts/tamm-framework.md,prompts/spec-investigation.md, the split of the spec review intoprompts/spec-reviewer.md,grounding.md,implementability.md,verdicts.md,spec-triage.mdandspec-fix.md, andprompts/spec-template.md,fix-spec-template.md,light-spec-template.md, andprompts/change-template.mdfor the oldtemplates/tasks-template.md). Install removes an unedited old copy (Removed <rel>: theway no longer ships it), renames an edited one to<rel>.bak(Moved your edited <rel> to <backup>: theway now reads prompts/<name>.md), so that it never becomes a standard every agent gets, and removes their.default.mdcopies.templates/keeps the three/theway:documenttemplates.
projects/<key>/: each project'schanges/folders, written by the commands, and its ownconfig.yaml,standards/,workflows/andprompts/.<key>is the project key thattheway projectprints in the repository. Earlier versions kept a project in<home>/<name>/, named after its directory; those folders are no longer read: move each one to the foldertheway projectprints.
-
~/.config/theway/home, only for a custom home (from--home, the home prompt orTHEWAY_HOME): the pointer file that holds the absolute data home, so the CLI finds it whenTHEWAY_HOMEis not set. With the default home (--home ~/.theway,THEWAY_HOMEset to~/.theway, or neitherTHEWAY_HOMEnor a pointer), install writes no pointer and removes an existing one. -
Two permission rules, added to
permissions.allowin~/.claude/settings.jsonwhen they are missing:Bash(theway:*): runs the CLI without a prompt.Read(~/.theway/**): reads the data home.
For a custom home, the
Readrule names its absolute path, such asRead(//data/tw/**).Writing change files (
spec.md,change.yaml,notes.md) goes through Claude Code's normal permission prompt; ticking a task withtheway task doneruns underBash(theway:*). Earlier versions also addedEdit(~/.theway/*/changes/**); install and uninstall remove it.
If ~/.claude/settings.json is not valid settings JSON, install stops and changes nothing.
Bash(theway:*) approves whichever theway comes first on your PATH, not only the copy install wrote. Install lists every theway on PATH and warns, naming it, when the first one is not its copy:
theway: warning: /usr/local/bin/theway comes before /home/you/.local/bin/theway on PATH, so the commands run it; theway copies on PATH: …From the old layout
Earlier versions installed the standards in data/standards/. On its first run over such a home, install moves each standard .shipped.json lists from data/standards/ to standards/ as it is, edited or not, with its .default.md copy, and renames its .shipped.json key with the same hash. It leaves a file in place, with a line, when standards/ already holds that name (Left data/standards/<name>: standards/<name> already exists) or theway no longer ships it (Left data/standards/<name>: theway no longer ships it); files .shipped.json does not list are never moved. It then removes data/standards/ and data/ when they are empty, and otherwise prints Left data/: it still holds files theway does not ship. An interrupted migration finishes on the next install.
Other locations
CLAUDE_CONFIG_DIRreplaces~/.claudewhen it is set.THEWAY_INSTALL_DIRreplaces~/.local/binwhen it is set. Pick a folder already on yourPATH, such as/opt/homebrew/bin. Set it again when you uninstall.--home <path>, orTHEWAY_HOME, replaces~/.thewayas the data home when it is given at install. Install records it in the pointer file, so nothing is written to~/.thewayand the commands find the home withoutTHEWAY_HOMEin Claude Code's environment.XDG_CONFIG_HOMEreplaces~/.configfor the pointer file.
The CLI looks for the data home in this order: THEWAY_HOME when it is set in its environment, then the pointer file, then ~/.theway. To change the home, run install again with the new value in --home or THEWAY_HOME: it rewrites the pointer, adds the rules of the new home and drops the Read and Edit rules of the previous one. Your existing data is not moved. Until then, theway path warns that THEWAY_HOME and the pointer differ.
Install refuses a data home that is your home folder or one of its parents, or a custom home that contains a glob character (*?[]{}) or a line break, whether it comes from --home or THEWAY_HOME: the permission rules it writes would cover far more than theway's files. It exits 1 and changes nothing.
Install finds the data home the same way, with --home first. Without --home or THEWAY_HOME, it updates the home the pointer names, so a reinstall from a shell that does not export THEWAY_HOME keeps a custom home. To go back to ~/.theway, run install with --home ~/.theway or THEWAY_HOME=~/.theway.
Upgrading from 0.2.0
theway 0.2.0 installed the CLI in the data home, as bin/theway and bin/theway.js, with the rule Bash(~/.theway/bin/theway:*) (or the absolute path for a custom home). Installing this version over it removes those two files when they are the ones 0.2.0 wrote, the bin/ folder when nothing else is in it, and the old rule. Your config and change folders stay where they are.
Changes written before change.yaml
Earlier versions kept a change's tasks in tasks.md. A change folder with a tasks.md and no change.yaml reads as invalid (invalid: not found in theway list), and theway archive refuses it. After it installs, install counts those active changes across every project and prints one line when there are any:
2 changes still use tasks.md: they read as invalid until each has a change.yaml; see https://pixelfactoryio.github.io/theway/docs/installation/#changes-written-before-changeyamltheway ships no converter. To convert one change by hand, in its folder:
- Write a
change.yamlwithversion: theway.change/v1beta, adescriptionof one line on what the change does, andtaskswith one item per- [ ] N.or- [x] N.line oftasks.md, in order: itstextwithout the number, anddone: truefor a[x]line. - Move the
## Notespart oftasks.mdtonotes.md. - Remove the
**Series:**line fromspec.md. - Delete
tasks.md.
theway change <change-id> exits 0 when the file is right, and prints each error otherwise. To archive an old change as it is instead, run theway archive <change-id> --force.