theway

CLI

The theway command line and its fifteen subcommands.

The theway program has fifteen subcommands: install, uninstall, list, archive, change, task done, path, project, config, standards, context, workflow, authority, validate-id and next-id. Install writes it to ~/.local/bin/theway (or $THEWAY_INSTALL_DIR/theway), and the slash commands call it as plain theway, so its folder must be on your PATH. See Installation.

theway install [--home <path>] [--standards <keys>]
theway uninstall
theway list [--project <key>]
theway archive <change-id> [--force] [--project <key>]
theway change <change-id> [--project <key>]
theway task done <change-id> <n>... [--project <key>]
theway path [<change-id>] [--verbose] [--project <key>]
theway project [--project <key>]
theway config [--project <key>]
theway standards <engineering|develop|document> [--project <key>]
theway context <engineering|develop|document> [<change-id>] [--project <key>]
theway workflow [<name>] [--input <name>=<value>]... [--compact] [--project <key>]
theway authority
theway validate-id <id> [--series]
theway next-id <series-id> [--count <n>] [--project <key>]

It needs Node.js 22.12 or later and exits 1 with a message on older versions.

Locations

The data home holds the config, the standards, the templates and the change folders. The CLI resolves it on every run, in this order:

  1. THEWAY_HOME, when it is set and not empty.
  2. The pointer file ${XDG_CONFIG_HOME:-~/.config}/theway/home, when it exists and is not empty. Install writes it whenever the resulting home is not the default: one chosen with --home or the install question, one set by THEWAY_HOME, or the custom home an earlier pointer names on a reinstall.
  3. ~/.theway.

theway path --verbose says which one it used.

Every subcommand that uses a project derives its key from the current directory (see project); --project <key> replaces it. A project's files live in <home>/projects/<key>/.

User standards live in <home>/standards/ (every project) and <home>/projects/<key>/standards/ (one project). Install never touches them.

Other environment variables:

  • CLAUDE_CONFIG_DIR replaces ~/.claude.
  • THEWAY_INSTALL_DIR replaces ~/.local/bin, for install and uninstall.

install

npx --yes @pixelfactoryio/theway@latest install

Copies the plugin to ~/.claude/skills/theway, the CLI to ~/.local/bin/theway, sets up the data home (--home, else THEWAY_HOME, else the home the pointer names, else ~/.theway), writes or removes the pointer file and adds the two permission rules to ~/.claude/settings.json, always dropping the Edit rule earlier versions added for the new and the previous home, and dropping the previous home's Read rule when the home changed. It stops and changes nothing when ~/.local/bin/theway is another program, not a theway binary. It also stops and changes nothing when the data home is your home folder or one of its parents, or a custom home containing a glob character or a line break. It prints the export PATH=… line when the install folder is not on PATH, and warns when another theway comes first on PATH. Run it through npx, which carries the plugin files; the installed theway install exits 1 and prints the npx command. See What install writes.

On a first install from a terminal (stdin and stdout), it asks where to keep the data home, only when theway was never installed, then which opt-in standards to enable, only when the data home has no config.yaml. The options answer without a question:

  • --home <path>: the data home, an absolute path or one starting with ~/.
  • --standards <keys>: the opt-in standards to enable in a new config.yaml, comma-separated (core_principles, sre, web_development, quality), or none.

It exits 1 and changes nothing when:

  • --home is not an absolute path and does not start with ~/: theway: invalid --home '<value>': <reason>; nothing was changed, with <reason> must be an absolute path or start with ~/, or must not be empty for a value of only spaces (an empty --home '' is refused by the argument parser);
  • --home and a set THEWAY_HOME name different paths: theway: --home <a> and THEWAY_HOME <b> differ; unset THEWAY_HOME or drop --home; nothing was changed;
  • --standards names an unknown key: theway: unknown standard '<element>' in --standards; valid: core_principles, sre, web_development, quality, or none;
  • --standards combines none with a key: theway: --standards none cannot be combined with other standards;
  • --standards is given and the data home already has a config.yaml: theway: --standards applies only to a first install; <home>/config.yaml exists, so set standards.<key>.enabled there instead; nothing was changed;
  • you cancel a question: theway: install cancelled; nothing was changed.

With no terminal and no --standards, a first install leaves the opt-in standards off and prints the line that says how to enable one.

uninstall

npx --yes @pixelfactoryio/theway@latest uninstall

Removes ~/.claude/skills/theway, ~/.local/bin/theway when it is a theway binary, the pointer file and the permission rules of THEWAY_HOME, of the home the pointer names and of ~/.theway. The data home is kept.

list

theway list

Prints a header line, theway changes — <key>, then the active changes of the project, then the archived change folders and a summary line. An active change is one line, <change-id> <files> files <done>/<total> tasks done, the ID padded to 20 characters: <files> counts every regular, non-hidden file directly in the change folder, and the tasks are those of its change.yaml. A change whose change.yaml is missing or invalid shows its first error in place of the count: invalid: not found, invalid: version: must be theway.change/v1beta. Used by /theway:list and /theway:archive.

A --project value must follow the rule of project, and a derived key must be at most 200 characters; otherwise it exits 1 with one line on stderr.

archive

theway archive <change-id> [--force]

Moves <home>/projects/<key>/changes/<change-id> to <home>/projects/<key>/changes/archive/YYYY-MM-DD-<change-id>, with today's local date, and prints Archived: <path>.

It exits 1 and moves nothing when:

  • the key is invalid (see project) or <change-id> does not follow the rule of path;

  • the change folder does not exist;

  • the archive folder already exists;

  • its change.yaml is invalid:

    Error: <change-id> has an invalid change.yaml — not archiving.
    changes/<change-id>/change.yaml: <where>: <message>
    Fix it, or re-run with --force.
  • a task of its change.yaml is open. It prints each one with its number and the first line of its text:

    Error: <change-id> has open tasks — not archiving.
    2. Answer 429 with a `Retry-After` header when the bucket is empty
    Tick them with theway task done, or re-run with --force.

--force archives anyway and prints WARNING: archiving with an invalid change.yaml (--force), or WARNING: archiving with open tasks (--force): followed by the open tasks.

change

theway change <change-id>

Validates <home>/projects/<key>/changes/<change-id>/change.yaml, the file that holds a change's description and its tasks:

version: theway.change/v1beta
description: Limit requests per API key with a token bucket
tasks:
  - text: Add a token bucket per API key, kept in memory
    done: true
  - text: Answer 429 with a `Retry-After` header when the bucket is empty
  - text: Read the limit and the burst from the settings
WhereRuleMessage
fileexists and is a YAML mapnot found · invalid YAML: <reason> · must be a map
any nodeno anchor (&name) and no alias (*name)anchors and aliases are not allowed
versionrequired, exactly theway.change/v1betamust be theway.change/v1beta
descriptionrequired, a non-empty string on one linemust be a non-empty string on one line
tasksrequired, a list with at least one itemmust be a list with at least one task
tasks[i]a mapmust be a map
tasks[i].textrequired, a non-empty stringmust be a non-empty string
tasks[i].doneoptional, true or false; absent means falsemust be true or false
any other keyat the root or in a taskunknown key

A task's number is its position in the list, counted from 1; tasks[i] in an error is counted from 0. A missing required key is reported as <key>: is required. Every error is reported, in the file's key order, then the missing keys.

Anchors and aliases are checked first: each one gives its own line, in document order, and no other rule is checked. The line's <where> is the path of the node in the table above, never deeper: a map key takes the path of the map that holds it, and a node below a root key's value or below tasks[i].<key> the path of its nearest ancestor the table names (description: [&a x] gives description, tasks[0].text: {k: &a v} gives tasks[0].text). An anchor on the file's root map has no <where>: the line is anchors and aliases are not allowed.

When the file is valid, it prints the change as JSON on stdout and exits 0:

{
  "id": "<change-id>",
  "dir": "<change folder>",
  "description": "…",
  "tasks": [
    {
      "n": 1,
      "text": "…",
      "done": true
    }
  ]
}

When it is not, it prints each error on stderr and exits 1, with nothing on stdout:

theway: changes/<change-id>/change.yaml: not found
theway: changes/<change-id>/change.yaml: tasks[1].done: must be true or false

The scaffold and fix-spec run it after writing a change.yaml, and fix the file until it exits 0. The key and the change ID follow the rules of archive.

task done

theway task done <change-id> <n>...

Ticks the tasks numbered <n> of the change's change.yaml: it sets done: true on each and keeps the rest of the file (comments, key order, line endings and its mode). An inserted done: true line ends as the line it follows (\r\n in a CRLF file). A task already done stays done. It prints <done>/<total> tasks done and exits 0.

It exits 1 and writes nothing when the file is invalid (with the error lines of change), or with one line per bad argument, in the order given, when an argument is not a task number (digits not starting with 0) or is greater than the number of tasks:

theway: changes/<change-id>/change.yaml: task 01: not a task number
theway: changes/<change-id>/change.yaml: task 9: no such task (1 to 3)

When the file or its folder cannot be written, it exits 1 with one line, the file left as it was:

theway: changes/<change-id>/change.yaml: cannot write: EACCES: permission denied, access '<path>'

The implementer runs it when a task is finished. To undo a tick, edit change.yaml. theway task alone prints its help.

path

theway path
theway path <change-id>

Prints one line on stdout:

  • theway path: the data home, such as /home/you/.theway. It derives no key; a given --project is still validated.
  • theway path <change-id>: <home>/projects/<key>/changes/<change-id>, whether or not the folder exists yet, such as /home/you/.theway/projects/-home-you-code-my-api/changes/add-x in /home/you/code/my-api. A single argument is always a change ID.

The slash commands run it to find the home (for the config, standards and templates) and the change folder they read and write.

--verbose adds one line on stderr naming where the home came from:

theway: home /data/tw (from pointer)

The source is env, pointer or default. When THEWAY_HOME is set and differs from the pointer file, it prints the THEWAY_HOME value and one warning on stderr that names both values and their sources. Run install again with the new THEWAY_HOME to update the pointer.

A change id must be lowercase letters and digits in words separated by single hyphens (as validate-id produces), at most 200 characters. Any other value exits 1 with one reason on stderr:

theway: invalid change id '..': must be lowercase letters and digits in words separated by single hyphens

The key is checked first, as project says.

project

theway project
theway project --project <key>

Prints the project key and the project folder, in /home/you/code/my-api:

key: -home-you-code-my-api
dir: /home/you/.theway/projects/-home-you-code-my-api

The key is the project root's absolute path with every character outside [A-Za-z0-9] replaced by -, as Claude Code names its ~/.claude/projects/ folders. The project root is:

  • in a git repository, any of its subfolders or a linked worktree: the main repository's root (git's common directory, .git, without its last segment), so every worktree shares one key;
  • in a bare repository or one with a separate git dir: the worktree root (git rev-parse --show-toplevel), else the current directory;
  • outside git, or without git on PATH: the current directory.

The root is resolved to its physical path (symlinks followed) before the key is built. A linked worktree of a --separate-git-dir repository and a submodule get their own worktree root, so they do not share the main repository's key. See Project key.

--project <key> replaces the derived key; no git command runs. Every subcommand that uses a project takes it: list, archive, change, task done, path, project, config, standards, context, workflow and next-id. It exits 1 with one line on stderr when:

  • the --project value is not letters, digits and -, 1 to 200 characters:

    theway: invalid project 'a/b': must be letters, digits and "-", at most 200 characters
  • the derived key is longer than 200 characters:

    theway: project key for <root> is longer than 200 characters; pass --project <key>

Every subcommand checks the key first, then its other arguments; an empty <change-id> for archive and an invalid --count for next-id are refused by the argument parser before it.

config

theway config

Prints the effective configuration of the project as YAML on stdout: the defaults, then <home>/config.yaml, then <home>/projects/<key>/config.yaml when it exists, merged key by key (see Layering). It prints every key, without comments, and every value it prints is valid. /theway:engineering, with or without --light, takes its keys from the same config, through context.

The standards section lists every switchable standard of the project, each as <key>: with its effective enabled: the four opt-in keys core_principles, sre, web_development and quality first, then the keys of the user standards of <home>/standards/ and <home>/projects/<key>/standards/, sorted.

standards:
  core_principles:
    enabled: false
  ...

An invalid value, an unknown key, a section that is not a map or a file whose root is not a map is ignored with a warning on stderr, the global file's first, and the exit code stays 0. <file> is the path relative to the home, config.yaml or projects/<key>/config.yaml:

theway: warning: <file>: <key> must be <rule>; ignored
theway: warning: <file>: unknown key <key>; ignored
theway: warning: <file>: <key> must be a map; ignored
theway: warning: <file>: not a map; ignored
theway: warning: <file>: standards.<key> has no standard file; ignored
theway: warning: <file>: standards.<key> cannot be switched; ignored

A workflow key, which earlier versions read for workflow.defaults, is an unknown key now: theway: warning: config.yaml: unknown key workflow; ignored. Set the value in the workflow file or in the prompt's header, and remove the key.

The standards warnings name a standards key that no standard file of the project gives, and the key of a standard that cannot be switched: one that is always read (interaction, develop, authority, tamm_framework, spec_review, spec_investigation), unless the project's <home>/projects/<key>/standards/ holds a file with that name (or, for authority, unless the global authority.md is one .shipped.json does not list, which makes it a user standard), or a convention standard (commits, git_host).

It exits 1 and prints nothing on stdout when:

  • the key is invalid, with the line of project on stderr;

  • <home>/config.yaml is missing:

    theway: config.yaml not found in <home>; run npx --yes @pixelfactoryio/theway@latest install, then /reload-plugins
  • either file exists but cannot be read:

    theway: <file>: cannot be read
  • either file is not valid YAML, duplicate keys included:

    theway: <file>: invalid YAML: Map keys must be unique at line 3, column 3

standards

theway standards engineering
theway standards develop
theway standards document

Prints the absolute path of every enabled standard that applies to the phase, one per line: the regular .md files directly in <home>/standards/, then directly in <home>/projects/<key>/standards/, each group sorted by name. Subfolders and other files are ignored. In <home>/standards/, interaction.md, develop.md, tamm-framework.md, spec-review.md and spec-investigation.md are never listed, nor authority.md when .shipped.json lists standards/authority.md (one it does not list is your own standard, key authority, listed and switched like any other); commits.md and git-host.md, the convention standards, are never listed from either folder; core-principles.md, sre.md, web-development.md and quality.md are the opt-in standards; the other files that .shipped.json lists as standards/<name>, and any *.default.md copy there, belong to theway and are not listed. A project file with the same name as a global one replaces it for the phases the project file applies to; for the other phases, the global file is printed as usual.

  • A standard, opt-in or yours, applies to the phases its applies_to frontmatter lists (engineering, develop and/or document), or to all three without one.
  • A standard is printed only when its effective standards.<key>.enabled is true: it computes the project's config as config does, without printing its warnings. A missing <home>/config.yaml counts as empty, so the defaults apply: opt-in standards off, user standards on.

With nothing to print, it prints nothing and exits 0.

/home/you/.theway/standards/tdd.md
/home/you/.theway/projects/-home-you-code-my-api/standards/review.md

An enabled file whose applies_to has any other value or form is skipped for every phase, with a warning on stderr; the exit code stays 0:

theway: warning: <path>: applies_to must list engineering, develop and/or document; skipped

A file that cannot be read is skipped, with a warning on stderr; the others are still listed and the exit code stays 0:

theway: warning: <path>: cannot be read; skipped

It exits 1 and prints nothing on stdout when:

  • the key is invalid, with the line of project on stderr;

  • the phase is not engineering, develop or document:

    theway: invalid phase '<value>': must be engineering, develop or document
  • either config.yaml cannot be read or is not valid YAML, with the message of config.

The commands get the same list through context.

context

theway context <engineering|develop|document>
theway context <engineering|develop|document> <change-id>

Prints what a command loads in its first step, as one YAML document with these keys, in this order:

  • home: the data home, as path prints it;
  • project: the project key, as project prints it;
  • project_dir: the project folder, <home>/projects/<key>;
  • change_dir: only with <change-id>, the folder theway path <change-id> prints;
  • standards: the paths standards prints for the phase, as a list, [] when there are none;
  • config: the effective config config prints.
home: /home/you/.theway
project: -home-you-code-my-api
project_dir: /home/you/.theway/projects/-home-you-code-my-api
change_dir: /home/you/.theway/projects/-home-you-code-my-api/changes/add-redis-cache
standards:
  - /home/you/.theway/standards/tdd.md
config:
  standards:
    ...

It writes the warnings of config to stderr once. It exits 1 and prints nothing on stdout when the key is invalid (see project), when the phase is invalid (the message of standards), when <change-id> does not follow the rule of path, or when <home>/config.yaml is missing or a config file cannot be read or is not valid YAML (the messages of config).

/theway:document runs it with document. The shipped prompts run it too: prompts/change.md with develop and the change ID, taking change_dir as the change folder, and prompts/spec-review.md with engineering.

workflow

theway workflow
theway workflow <name>
theway workflow <name> --input <name>=<value> [--input <name>=<value>]...
theway workflow <name> --input <name>=<value> --compact

Reads one workflow and every prompt its steps use, checks them, and prints the resolved document as JSON on stdout. /theway:workflow runs it first to read the workflow's inputs, then with --input and --compact to get the document it runs.

Which file:

  • With <name>: <home>/projects/<key>/workflows/<name>.yaml when it is a file, else <home>/workflows/<name>.yaml. A <name> matches ^[a-z0-9]+(-[a-z0-9]+)*$; the workflow's name is its file stem.
  • Without <name>: the one workflow that sets default: true, among the project's workflow files and the global ones no project file of the same name hides. The shipped develop sets it. When none sets it, it exits 1 with theway: no workflow sets default: true; when several do, with a line naming them, for example theway: workflows/agents.yaml and workflows/develop.yaml both set default: true.
  • Each prompt a step names, prompts/<name>.md, is <home>/projects/<key>/prompts/<name>.md when it is a file, else <home>/prompts/<name>.md.
  • A *.default.yaml file is the shipped copy install writes next to an edited file, never a workflow.

--input <name>=<value>, repeatable, gives a workflow input its value. When every required input is given, the document says "resolved": true and every ${{ inputs.… }} and ${{ matrix.… }} reference is replaced in each run's prompt. Without --input, a workflow that declares a required input keeps its input references as written and says "resolved": false; one with no required input resolves with each input's default, else the empty string. Refused, each with one line: an input the workflow does not declare, an invalid change ID for an input of type: change, a value without =, a name given twice and, once any --input is given, a required input that is not given or is given empty (theway: --input <name>: required input is not given).

theway workflow agents --input change=add-foo, with the shipped agents.yaml (shortened):

{
  "name": "agents",
  "version": "theway.workflow/v1beta",
  "description": "Implement, review and open the PR through agents",
  "file": "/home/you/.theway/workflows/agents.yaml",
  "default": false,
  "inputs": {
    "change": { "description": "The change to implement", "required": true, "default": null, "type": "change", "value": "add-foo" }
  },
  "runs_on": "agents",
  "resolved": true,
  "steps": [
    {
      "index": 0,
      "uses": "prompts/branch.md",
      "file": "/home/you/.theway/prompts/branch.md",
      "description": "Sync the default branch and create or check out the change's feature branch",
      "runs_on": "session",
      "model": null,
      "matrix": null,
      "with": { "change": "${{ inputs.change }}" },
      "runs": [{ "label": "1.branch", "with": { "change": "add-foo" }, "prompt": "# Branch\n\nYou prepare the feature branch of the change `add-foo`. …" }],
      "on_fail": null,
      "tries": null
    },
    { "index": 1, "uses": "prompts/implement.md", "...": "..." },
    {
      "index": 2,
      "uses": "prompts/review.md",
      "runs_on": "agents",
      "model": "opus",
      "matrix": { "key": "lens", "values": ["prompts/conformance.md", "prompts/correctness.md"] },
      "runs": [
        { "label": "3.review[prompts/conformance.md]", "...": "..." },
        { "label": "3.review[prompts/correctness.md]", "...": "..." }
      ],
      "...": "..."
    },
    {
      "index": 3,
      "uses": "prompts/triage.md",
      "...": "...",
      "on_fail": { "uses": "prompts/fix-review.md", "model": "opus", "label": "4.fix-review", "prompt": "# Fix the Review\n\n…", "...": "..." },
      "tries": 1
    },
    { "index": 4, "uses": "prompts/open-pr.md", "...": "..." },
    { "index": 5, "uses": "prompts/ci.md", "...": "...", "tries": 2 }
  ]
}
  • inputs holds each declared input with its value: the given one, else its default, else ""; null while the document is not resolved.
  • Each step has its index, uses and the prompt's absolute file and description, its effective runs_on (its own, else the workflow's) and model (its own, else its prompt's; null for a step that runs in your session), its matrix, its with as written, its runs and its on_fail and tries.
  • A step has one run, or one per matrix value. Each run has its label, <n>.<prompt> (<n>.<prompt>[<value>] for a matrix copy), every input of its prompt with its final value, and the prompt's body with the values substituted.
  • The on_fail has its own label, <n>.<prompt>, model and prompt.

--compact prints the same document without its bulky text, for a session to pass on whole. It checks the workflow the same way and fails with the same lines.

  • The top level keeps name, file, resolved, runs_on and inputs, each with its value.
  • Each step keeps index, uses, file, runs_on, model, matrix, runs, on_fail and tries; no description and no with as written.
  • Each run keeps its label and its with, the final values; the on_fail its uses, file, model, label and with. Neither has a prompt: an agent reads the prompt's file and uses the with values where its text says ${{ inputs.<name> }}.
{
  "name": "agents",
  "file": "/home/you/.theway/workflows/agents.yaml",
  "resolved": true,
  "runs_on": "agents",
  "inputs": {
    "change": { "description": "The change to implement", "required": true, "default": null, "type": "change", "value": "add-foo" }
  },
  "steps": [
    {
      "index": 0,
      "uses": "prompts/branch.md",
      "file": "/home/you/.theway/prompts/branch.md",
      "runs_on": "session",
      "model": null,
      "matrix": null,
      "runs": [{ "label": "1.branch", "with": { "change": "add-foo" } }],
      "on_fail": null,
      "tries": null
    },
    { "index": 1, "uses": "prompts/implement.md", "...": "..." },
    { "index": 2, "uses": "prompts/review.md", "...": "..." },
    {
      "index": 3,
      "uses": "prompts/triage.md",
      "...": "...",
      "on_fail": {
        "uses": "prompts/fix-review.md",
        "file": "/home/you/.theway/prompts/fix-review.md",
        "model": "opus",
        "label": "4.fix-review",
        "with": { "change": "add-foo" }
      },
      "tries": 1
    },
    { "index": 4, "uses": "prompts/open-pr.md", "...": "..." },
    { "index": 5, "uses": "prompts/ci.md", "...": "...", "tries": 2 }
  ]
}

A file whose version is theway.workflow/v1 is no longer read:

theway: workflows/<name>.yaml: theway.workflow/v1 is no longer read: rewrite it as theway.workflow/v1beta

Moving from v1 says what replaces each of its parts.

Every mistake of the file and of the prompts it uses is one line on stderr, theway: <file>: <place>: <message>, in file order; it then prints nothing on stdout and exits 1. <file> is the path relative to the home, or the folder that holds it:

theway: invalid workflow name '<name>'
theway: workflows/w.yaml: not found in <home>/projects/<key>/workflows or <home>/workflows
theway: workflows/w.yaml: version: must be theway.workflow/v1beta
theway: workflows/w.yaml: steps[0].uses: prompts/nope.md not found in <home>/projects/<key>/prompts or <home>/prompts
theway: workflows/w.yaml: steps[1].with: required input change is not set
theway: workflows/w.yaml: steps[2].on-fail: needs tries (an integer from 1 to 10)
theway: prompts/open-pr.md: body: ${{ inputs.nope }} names no input of this prompt
theway: --input change: required input is not given

Validation describes every rule. It also exits 1 with the line of project for an invalid key.

authority

theway authority

Prints the authority whole, without trailing blank lines. A file that is empty or holds only whitespace counts as missing.

  • When .shipped.json lists standards/authority.md, it prints <home>/standards/authority.md, else the shipped <home>/standards/authority.default.md. When neither can be printed, it exits 1:

    theway: no <home>/standards/authority.md; run npx --yes @pixelfactoryio/theway@latest install, then /reload-plugins
  • When .shipped.json does not list it, authority.md is your own standard (see standards), and it prints <home>/standards/authority.default.md only. When that cannot be printed, it exits 1:

    theway: no <home>/standards/authority.default.md; run npx --yes @pixelfactoryio/theway@latest install, then /reload-plugins

The commands that spawn agents quote its output verbatim in every agent prompt, and /theway:workflow, /theway:document and /theway:archive follow it in the session.

validate-id

theway validate-id <id>
theway validate-id <id> --series

Checks a change ID. It exits 0 when the ID is valid. Otherwise it exits 1 and prints one line on stderr:

invalid change id '<id>': <reason>

Every ID must be lowercase kebab-case ([a-z0-9] segments joined by single hyphens) and start with add-, update-, refactor-, remove- or fix-. An ID with uppercase letters is rejected with uppercase letters are not allowed; use lowercase kebab-case, one with underscores with underscores are not allowed; use kebab-case (-); any other start is rejected with:

invalid change id '<id>': must start with a verb prefix: add-, update-, refactor-, remove- or fix-
  • Without --series (a standalone change): the ID must not end in a one- or two-digit number.
  • With --series (a series member): the ID must end in a two-digit ordinal from 01, such as add-user-auth-01. Letter suffixes, -00 and double ordinals are rejected.

/theway:engineering, with or without --light, runs it before it writes a standalone change folder; next-id validates the members of a series.

next-id

theway next-id <series-id>
theway next-id <series-id> --count <n>

Prints the next <n> free member IDs of a series, one per line (--count defaults to 1):

add-user-auth-04
add-user-auth-05
  • A trailing -NN is removed from <series-id> first, so add-user-auth-07 gives the same IDs as add-user-auth. The rest must fit the validate-id format and must not end in a one- or two-digit number; when it is invalid, it exits 1 with an invalid change id '<id>': <reason> line, <id> being the series ID without its ordinal, for example:

    invalid change id 'add-thing-01': ends in a number (-01); a series id cannot end in a number
  • It counts the folders <home>/projects/<key>/changes/<series-id>-NN and the archived <home>/projects/<key>/changes/archive/YYYY-MM-DD-<series-id>-NN, and continues after the highest NN, or from 01 when there is none.

  • A --count that is not a positive integer is rejected with error: option '--count <n>' argument '<value>' is invalid. must be a positive integer. When the last ID would be past -99, it exits 1:

    theway: series <series-id> would go past -99

/theway:engineering runs it to name the members of a new series.

On this page