In short: --user prints every user config path jj considers, one per line, and creates nothing.
--repo and --workspace print one path, inside the user config directory under
jj/repos/<id>/ or jj/workspaces/<id>/. If that repo or workspace has
no config ID yet, jj makes one: it creates the directory, writes metadata.binpb there, and
writes the ID into .jj. The config.toml itself is not created.
The command is cmd_config_path. Its help text: "Print the paths
to the config files", noting that a file at that path may not exist and that a config directory is generated for
--repo or --workspace if needed (source). It is the
Path variant of ConfigCommand, with the visible alias jj config p
(source, dispatch).
To open the file in an editor instead, use jj config edit.
1. Command-line surface
| Flag | Meaning |
|---|---|
--user | The user-level config paths (source). |
--repo | The repo-level config file (source). |
--workspace | The workspace-level config file (source). |
Exactly one of the three is required: they form the clap group config_level with
multiple = false, required = true (source).
-R picks which repo and workspace --repo and --workspace refer to.
The global flags are on the CLI page.
2. Configuration
No config keys. The user paths come from the environment: if JJ_CONFIG is set, it is split like
PATH and its non-empty entries are the user paths; otherwise jj uses
~/.jjconfig.toml (only if it exists, or if there is no platform config directory), then
<config dir>/jj/config.toml, then <config dir>/jj/conf.d if that directory
exists (source). The repo and workspace paths live under
<config dir>/jj (source,
directory names). Output is the path's bytes and a newline, with no template.
3. End-to-end flow
4. Core architecture touchpoints
| Piece | Role here |
|---|---|
CommandHelper::config_env | The ConfigEnv built at startup. It already knows the user paths and, if a workspace was found, the repo and workspace directories (repo, workspace). |
SecureConfig | Finds a repo's or workspace's config file. The ID lives in .jj/repo/config-id or .jj/workspace-config-id; the file itself lives in the user config directory (source). Keeping it out of the repo means a cloned or downloaded repo cannot carry config that jj would load. |
ConfigMetadata | Stored as metadata.binpb next to the config file; it records which .jj or .jj/repo directory the config belongs to. |
5. What it reads, and snapshotting
It never snapshots and never loads the repo. --user only computes paths; upstream's test checks that
no file is created (test). --repo and
--workspace read the config ID file in .jj and the config directory's
metadata.binpb. When no ID exists they write: the new directory, its metadata.binpb, and
the ID file in .jj, written atomically through a temporary file
(source, atomic write). Upstream's test
checks that the legacy in-repo path .jj/repo/config.toml is not created
(test).
6. Algorithm and invariants
User paths
--user prints all of user_config_paths(), in order, and fails only if the list is empty
(source). A path may be a file or a conf.d-style directory
(test).
Repo and workspace paths
At startup jj already ran maybe_load_config, which does not create anything
(source). The command calls the forcing variant,
load_config: if the earlier lookup found a config, the cached
path is returned; if not, it generates a random 10-byte hex ID (source)
and sets up the directory. The lookup itself (source):
- An ID file that is not 20 hex characters is an error.
- An ID whose directory has no
metadata.binpbgets a fresh directory and a warning, "Per-repo config not found. Generating an empty one." (source). - If the metadata names a different directory, jj checks it (source). If that directory is gone, it assumes the repo moved and updates the metadata. If it still exists and is a separate copy, jj gives the copy its own ID and copies the config file, with a warning.
- With no ID file, a legacy
.jj/repo/config.tomlor.jj/workspace-config.tomlis migrated into a new config directory, with a warning (source).
7. Errors and edge cases
| Situation | Result |
|---|---|
--repo outside any repo | Error: No repo config path found, exit 1 (source, test). |
--workspace outside any workspace | Error: No workspace config path found (source, test). |
No user config path (for example JJ_CONFIG has only empty entries) | Error: No user config path found (source). |
| No level flag, or more than one | A clap usage error from the config_level group (source). |
| Malformed config ID file | "Found an invalid config ID" (source). |
| Path not valid as bytes on this platform | A user error from path_to_bytes (source). |
8. Example output
From upstream's tests, in a repo at $TEST_ENV/repo with JJ_CONFIG pointing at
$TEST_ENV/config.toml. The IDs are random; the tests fix the seed
(source, source):
repo$ jj config path --user
$TEST_ENV/config.toml
repo$ jj config path --repo
$TEST_ENV/home/.config/jj/repos/ffdaa62087a280bddc5e/config.toml
repo$ jj config path --workspace
$TEST_ENV/home/.config/jj/workspaces/d043564ef93650b06a70/config.toml
$ jj config path --repo
Error: No repo config path found
# with JJ_CONFIG listing a file and a directory
repo$ jj config path --user
$TEST_ENV/config/config.toml
$TEST_ENV/config/conf.d