claude-nomad 0.32.4 → 0.34.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +20 -0
- package/README.md +180 -200
- package/package.json +5 -6
- package/src/commands.doctor.version.ts +19 -22
- package/src/commands.update.ts +18 -179
- package/src/config.ts +1 -8
- package/src/init.gh-onboard.ts +139 -0
- package/src/init.ts +19 -1
- package/src/nomad.dispatch.ts +95 -0
- package/src/nomad.help.ts +13 -8
- package/src/nomad.ts +19 -20
- package/src/push-checks.ts +16 -10
- package/src/push-gitleaks.config.ts +161 -0
- package/src/push-gitleaks.scan.ts +35 -12
- package/src/commands.update.git.ts +0 -90
- package/src/commands.update.resolve.ts +0 -138
- package/src/commands.update.test-helpers.git.ts +0 -107
- package/src/update.fork-extras.ts +0 -102
- package/src/update.topology.ts +0 -118
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,25 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [0.34.0](https://github.com/funkadelic/claude-nomad/compare/v0.33.0...v0.34.0) (2026-05-31)
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
### ⚠ BREAKING CHANGES
|
|
7
|
+
|
|
8
|
+
* `nomad update` no longer self-updates via git/fork (it runs only `npm update -g claude-nomad`) and the `--push-origin` flag is removed. `nomad init` now requires the GitHub CLI (`gh`) on first-host setup when REPO_HOME has no `origin` remote.
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
|
|
12
|
+
* **push:** gitleaks allowlist base+overlay merge ([#201](https://github.com/funkadelic/claude-nomad/issues/201)) ([f6f2e8c](https://github.com/funkadelic/claude-nomad/commit/f6f2e8c62ef868b33f560170ddd8c60122eac4cb))
|
|
13
|
+
* standalone-repo onboarding as the default, retire fork model ([#199](https://github.com/funkadelic/claude-nomad/issues/199)) ([8d38df9](https://github.com/funkadelic/claude-nomad/commit/8d38df909c36eeda085f8d4eb78e706c4ad2f115))
|
|
14
|
+
|
|
15
|
+
## [0.33.0](https://github.com/funkadelic/claude-nomad/compare/v0.32.4...v0.33.0) (2026-05-30)
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
### Added
|
|
19
|
+
|
|
20
|
+
* **dist:** run bin under node native type-stripping, drop tsx ([#198](https://github.com/funkadelic/claude-nomad/issues/198)) ([79b437d](https://github.com/funkadelic/claude-nomad/commit/79b437d8fee69d4f0f25394de9236f7c67289291))
|
|
21
|
+
* **help:** show CLI version at the top of default help ([#196](https://github.com/funkadelic/claude-nomad/issues/196)) ([f095d35](https://github.com/funkadelic/claude-nomad/commit/f095d354273122bc530aac5f486fdb9ad771341e))
|
|
22
|
+
|
|
3
23
|
## [0.32.4](https://github.com/funkadelic/claude-nomad/compare/v0.32.3...v0.32.4) (2026-05-30)
|
|
4
24
|
|
|
5
25
|
|
package/README.md
CHANGED
|
@@ -41,7 +41,7 @@ box, a personal rig and a work machine. [Get started in three steps.](#quickstar
|
|
|
41
41
|
|
|
42
42
|
- [Quickstart](#quickstart)
|
|
43
43
|
- **Concepts**
|
|
44
|
-
- [How it works
|
|
44
|
+
- [How it works](#how-it-works)
|
|
45
45
|
- [Repo layout](#repo-layout-what-claude-nomad-looks-like-on-a-configured-host)
|
|
46
46
|
- [What gets synced vs. not](#what-gets-synced-vs-not)
|
|
47
47
|
- [Path remapping](#path-remapping)
|
|
@@ -52,10 +52,10 @@ box, a personal rig and a work machine. [Get started in three steps.](#quickstar
|
|
|
52
52
|
- [Requirements](#requirements)
|
|
53
53
|
- [Setup](#setup)
|
|
54
54
|
- [Privacy by default](#privacy-by-default)
|
|
55
|
-
- [
|
|
56
|
-
- [
|
|
55
|
+
- [First host](#first-host)
|
|
56
|
+
- [Each additional host](#each-additional-host)
|
|
57
57
|
- [Migrating an existing ~/.claude/](#migrating-an-existing-claude)
|
|
58
|
-
- [Upgrading the
|
|
58
|
+
- [Upgrading the CLI](#upgrading-the-cli)
|
|
59
59
|
- **Reference**
|
|
60
60
|
- [Commands](#commands)
|
|
61
61
|
- [Recovery flows](#recovery-flows)
|
|
@@ -64,31 +64,40 @@ box, a personal rig and a work machine. [Get started in three steps.](#quickstar
|
|
|
64
64
|
- [Recovery flow: gitleaks FATAL on a session JSONL](#recovery-flow-gitleaks-fatal-on-a-session-jsonl)
|
|
65
65
|
- [Recovery flow: push-time interactive menu](#recovery-flow-push-time-interactive-menu)
|
|
66
66
|
- [`.gitleaks.toml` allowlist policy](#gitleakstoml-allowlist-policy)
|
|
67
|
+
- [Customizing the allowlist with an overlay](#customizing-the-allowlist-with-an-overlay)
|
|
67
68
|
- [Cross-OS resume](#cross-os-resume)
|
|
68
69
|
- [Run tests](#run-tests)
|
|
69
70
|
|
|
70
71
|
## Quickstart
|
|
71
72
|
|
|
72
|
-
|
|
73
|
-
bootstrap), adding a new host is two one-time steps, then the everyday loop:
|
|
73
|
+
**First host** (once, ever):
|
|
74
74
|
|
|
75
75
|
```bash
|
|
76
|
+
# 1. Install the CLI.
|
|
76
77
|
$ npm i -g claude-nomad
|
|
77
|
-
```
|
|
78
78
|
|
|
79
|
-
|
|
80
|
-
#
|
|
81
|
-
$
|
|
79
|
+
# 2. Create your private sync repo and scaffold it. nomad init uses gh to
|
|
80
|
+
# create the repo, wire origin, and disable Actions, then scaffolds locally.
|
|
81
|
+
$ nomad init # prompts for a repo name (default: claude-nomad-config)
|
|
82
|
+
$ nomad init --repo my-config # non-interactive: use this name, no prompt
|
|
82
83
|
|
|
83
|
-
# Add to ~/.zshrc or ~/.bashrc
|
|
84
|
+
# 3. Add a stable host label to ~/.zshrc or ~/.bashrc, then reload.
|
|
84
85
|
export NOMAD_HOST=<your-host-label>
|
|
85
86
|
|
|
86
|
-
#
|
|
87
|
-
|
|
88
|
-
|
|
87
|
+
# 4. Publish the scaffold to your private repo.
|
|
88
|
+
$ nomad push
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
**Each additional host:**
|
|
92
|
+
|
|
93
|
+
```bash
|
|
94
|
+
$ npm i -g claude-nomad
|
|
95
|
+
$ gh repo clone <your-username>/claude-nomad-config ~/claude-nomad
|
|
96
|
+
export NOMAD_HOST=<your-host-label> # add to ~/.zshrc or ~/.bashrc
|
|
97
|
+
$ nomad pull
|
|
89
98
|
```
|
|
90
99
|
|
|
91
|
-
Then the everyday loop:
|
|
100
|
+
Then the everyday loop on any host:
|
|
92
101
|
|
|
93
102
|
```bash
|
|
94
103
|
$ nomad doctor # confirm setup
|
|
@@ -96,37 +105,33 @@ $ nomad pull # apply config to ~/.claude/
|
|
|
96
105
|
$ nomad push # publish local changes (sessions, settings)
|
|
97
106
|
```
|
|
98
107
|
|
|
99
|
-
|
|
100
|
-
|
|
108
|
+
Full walkthrough and the safe-migration sequence for a populated `~/.claude/` are in [Setup](#setup)
|
|
109
|
+
and [Migrating an existing ~/.claude/](#migrating-an-existing-claude).
|
|
101
110
|
|
|
102
|
-
## How it works
|
|
111
|
+
## How it works
|
|
103
112
|
|
|
104
|
-
**claude-nomad** is a **tool**, not a config store. You
|
|
105
|
-
|
|
106
|
-
|
|
113
|
+
**claude-nomad** is a **tool**, not a config store. You install the CLI globally
|
|
114
|
+
(`npm i -g claude-nomad`) and keep a separate **private** Git repo that holds only your config:
|
|
115
|
+
`CLAUDE.md`, agents, skills, settings, session transcripts. No tool source code lives in that repo.
|
|
107
116
|
|
|
108
117
|
```text
|
|
109
|
-
|
|
110
|
-
├──
|
|
111
|
-
├──
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
│ └── projects/
|
|
122
|
-
├── hosts/<hostname>.json
|
|
123
|
-
└── path-map.json
|
|
118
|
+
your private <your-username>/claude-nomad-config
|
|
119
|
+
├── shared/ (your config, synced to every host)
|
|
120
|
+
│ ├── CLAUDE.md
|
|
121
|
+
│ ├── agents/
|
|
122
|
+
│ ├── skills/
|
|
123
|
+
│ ├── commands/
|
|
124
|
+
│ ├── rules/
|
|
125
|
+
│ ├── hooks/
|
|
126
|
+
│ ├── settings.base.json
|
|
127
|
+
│ └── projects/
|
|
128
|
+
├── hosts/<hostname>.json
|
|
129
|
+
└── path-map.json
|
|
124
130
|
```
|
|
125
131
|
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
sync.
|
|
132
|
+
`nomad init` creates this repo for you (via `gh`) and scaffolds the directory structure in one step.
|
|
133
|
+
Every host after the first installs the CLI, clones your private data repo to `~/claude-nomad/`, and
|
|
134
|
+
runs `nomad pull` to sync.
|
|
130
135
|
|
|
131
136
|
By default the CLI operates on `~/claude-nomad/` (see `REPO_HOME` in `src/config.ts`). Developers
|
|
132
137
|
working from an alternate checkout can `export NOMAD_REPO=/path/to/repo` to point the CLI at their
|
|
@@ -138,8 +143,6 @@ so a clobbered dotfile variable does not break the CLI.
|
|
|
138
143
|
|
|
139
144
|
```text
|
|
140
145
|
~/claude-nomad/
|
|
141
|
-
├── src/ # the CLI (came from the public tool repo)
|
|
142
|
-
├── scripts/ # helper scripts you add
|
|
143
146
|
├── shared/ # synced to every machine
|
|
144
147
|
│ ├── CLAUDE.md
|
|
145
148
|
│ ├── settings.base.json # baseline settings
|
|
@@ -156,8 +159,7 @@ so a clobbered dotfile variable does not break the CLI.
|
|
|
156
159
|
│ ├── <your-mac>.json # patches merged over settings.base.json
|
|
157
160
|
│ ├── <your-wsl-host>.json
|
|
158
161
|
│ └── <your-nuc>.json
|
|
159
|
-
|
|
160
|
-
└── package.json, ... (tool metadata)
|
|
162
|
+
└── path-map.json # logical project -> per-host absolute path
|
|
161
163
|
```
|
|
162
164
|
|
|
163
165
|
## What gets synced vs. not
|
|
@@ -350,9 +352,9 @@ Results on `your-other-host`: opus 4.8, the local Ollama env var, plus the share
|
|
|
350
352
|
|
|
351
353
|
`nomad doctor` warns when `settings.json` carries a top-level key it does not recognize (a cue that
|
|
352
354
|
Claude Code added a setting). The recognized set is kept current against Claude Code's published
|
|
353
|
-
settings schema by a weekly automated PR in the public repo, so a periodic `nomad update`
|
|
354
|
-
keeps that warning quiet on your hosts. To check your own `settings.json`
|
|
355
|
-
demand, run `nomad doctor --check-schema`.
|
|
355
|
+
settings schema by a weekly automated PR in the public repo, so a periodic `nomad update` (to get
|
|
356
|
+
the latest CLI) is what keeps that warning quiet on your hosts. To check your own `settings.json`
|
|
357
|
+
against the live schema on demand, run `nomad doctor --check-schema`.
|
|
356
358
|
|
|
357
359
|
## What does NOT sync (deliberate trade-offs)
|
|
358
360
|
|
|
@@ -381,104 +383,61 @@ Read these before adopting so you opt in with eyes open.
|
|
|
381
383
|
- Node.js 22.22.1 or newer (24 LTS recommended; the npm `engines` field declares the 22.22.1 floor
|
|
382
384
|
and surfaces a warning on older runtimes - npm only blocks the install when `engine-strict=true`
|
|
383
385
|
is configured)
|
|
384
|
-
- `tsx` (ships as a runtime dependency of the published package; no separate global install
|
|
385
|
-
required)
|
|
386
386
|
- Git
|
|
387
387
|
- [`gitleaks`](https://github.com/gitleaks/gitleaks) (required for `nomad push`, which exits with an
|
|
388
388
|
error if it is not on PATH; `nomad doctor` also checks it against the pinned 8.30.x and warns when
|
|
389
389
|
it is absent or mismatched)
|
|
390
|
-
-
|
|
390
|
+
- `gh` ([GitHub CLI](https://cli.github.com/)), required by `nomad init` to create and wire the
|
|
391
|
+
private sync repo. When `gh` is missing or unauthenticated, `nomad init` exits with a FATAL and
|
|
392
|
+
shows install / `gh auth login` guidance. On hosts where the private repo is already set up (all
|
|
393
|
+
subsequent hosts), `gh` is only needed by `nomad doctor`'s Actions-drift check and auto-disable;
|
|
394
|
+
pull and push work without it.
|
|
391
395
|
|
|
392
|
-
**Optional
|
|
396
|
+
**Optional:**
|
|
393
397
|
|
|
394
|
-
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
and the post-`nomad update` check) and by `nomad doctor --check-schema`; it degrades silently when
|
|
399
|
-
curl is absent or offline, so the rest of the CLI works without it. `nomad doctor` reports its
|
|
400
|
-
presence in the Version Checks section.
|
|
398
|
+
- [curl](https://curl.se/), used by the version-staleness check (`nomad doctor` latest-release line)
|
|
399
|
+
and by `nomad doctor --check-schema`; it degrades silently when curl is absent or offline, so the
|
|
400
|
+
rest of the CLI works without it. `nomad doctor` reports its presence in the Version Checks
|
|
401
|
+
section.
|
|
401
402
|
|
|
402
403
|
## Setup
|
|
403
404
|
|
|
404
|
-
**Why not just fork?** GitHub doesn't let you flip a public fork to private, and your config
|
|
405
|
-
(especially session transcripts) must stay private. So the bootstrap is a one-time mirror-push into
|
|
406
|
-
a fresh private repo, not a fork.
|
|
407
|
-
|
|
408
405
|
### Privacy by default
|
|
409
406
|
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
automatically:
|
|
407
|
+
Your private sync repo must stay private. Session transcripts contain the full text of your
|
|
408
|
+
conversations. `nomad init` disables Actions on the new repo as soon as it is created, via the
|
|
409
|
+
GitHub API call `gh api -X PUT repos/<owner>/<repo>/actions/permissions -F enabled=false`. What this
|
|
410
|
+
means for you: CI workflows (which could echo transcript content into build logs) are turned off on
|
|
411
|
+
your private data repo automatically; you do not need to remember to do it.
|
|
416
412
|
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
private"), so even with Actions enabled the jobs do not run on your mirror.
|
|
420
|
-
2. **`nomad init` turns Actions off for the whole repo** on first run, via the GitHub API call
|
|
421
|
-
`gh api -X PUT repos/<owner>/<repo>/actions/permissions -F enabled=false`. This needs the `gh`
|
|
422
|
-
CLI installed and authed; if it is missing or unauthed, init logs a manual fallback tip and
|
|
423
|
-
continues.
|
|
424
|
-
|
|
425
|
-
Pass `--keep-actions` to either form of init to skip step 2 (for example, when your org already
|
|
426
|
-
enforces an Actions policy upstream).
|
|
413
|
+
Pass `--keep-actions` to skip the disable step (for example, when your org already enforces an
|
|
414
|
+
Actions policy).
|
|
427
415
|
|
|
428
416
|
<!-- prettier-ignore -->
|
|
429
417
|
> [!WARNING]
|
|
430
|
-
> If you ever
|
|
431
|
-
>
|
|
432
|
-
> content) become world-readable. **Keep it private.**
|
|
418
|
+
> If you ever make the repo public, your session transcripts (which include conversation content)
|
|
419
|
+
> become world-readable. **Keep it private.**
|
|
433
420
|
|
|
434
|
-
###
|
|
421
|
+
### First host
|
|
435
422
|
|
|
436
|
-
|
|
423
|
+
`nomad init` creates the private repo via `gh`, wires it as `origin`, disables Actions, scaffolds
|
|
424
|
+
the directory layout, and pushes. The `gh` CLI must be installed and authenticated before you run
|
|
425
|
+
it.
|
|
437
426
|
|
|
438
427
|
```bash
|
|
439
|
-
#
|
|
440
|
-
$ gh repo create <your-username>/claude-nomad --private
|
|
441
|
-
|
|
442
|
-
# 2. Copy the public tool into your private repo. A bare clone followed by a
|
|
443
|
-
# mirror push makes a complete, independent copy (every branch and tag) with
|
|
444
|
-
# no fork link back to upstream, which is what lets you keep it private. Once, ever.
|
|
445
|
-
$ git clone --bare git@github.com:funkadelic/claude-nomad.git /tmp/claude-nomad.git # download a full copy
|
|
446
|
-
$ cd /tmp/claude-nomad.git
|
|
447
|
-
$ git push --mirror git@github.com:<your-username>/claude-nomad.git # upload it to your private repo
|
|
448
|
-
$ cd .. && rm -rf /tmp/claude-nomad.git
|
|
449
|
-
|
|
450
|
-
# 3. Install the CLI globally and clone your private copy. Repeat on every host.
|
|
428
|
+
# Install the CLI.
|
|
451
429
|
$ npm i -g claude-nomad
|
|
452
|
-
$ git clone git@github.com:<your-username>/claude-nomad.git ~/claude-nomad
|
|
453
|
-
|
|
454
|
-
# 4. Add a stable host label to your shell rc (~/.zshrc or ~/.bashrc). Repeat on every host.
|
|
455
|
-
export NOMAD_HOST=<your-host-label> # any short, stable label; nomad reads this instead of os.hostname()
|
|
456
|
-
```
|
|
457
|
-
|
|
458
|
-
`npm i -g claude-nomad` puts a `nomad` binary on your PATH. The bin shim is the existing
|
|
459
|
-
`src/nomad.ts` entrypoint resolved through tsx (a runtime dependency); no compile step. (The Node
|
|
460
|
-
version floor and the `engine-strict` caveat are in [Requirements](#requirements).)
|
|
461
|
-
|
|
462
|
-
On every additional host you repeat only steps 3-4; steps 1-2 are already done, since your private
|
|
463
|
-
repo lives on the remote from step 2.
|
|
464
|
-
|
|
465
|
-
`NOMAD_HOST` overrides `os.hostname()`, which returns noisy values like `WINDOWS-I5NT6OH` on WSL or
|
|
466
|
-
`<name>.local` on macOS. Pick a clean label per machine (e.g., `wsl-laptop`, `macbook`,
|
|
467
|
-
`homelab-nuc`). `nomad doctor` reports the resolved host so you can confirm.
|
|
468
|
-
|
|
469
|
-
### Initialize the repo layout
|
|
470
|
-
|
|
471
|
-
First host only; subsequent hosts just clone and `nomad pull`. Both forms below auto-disable Actions
|
|
472
|
-
on a detected private GitHub mirror as described in [Privacy by default](#privacy-by-default). Pick
|
|
473
|
-
one:
|
|
474
430
|
|
|
475
|
-
|
|
476
|
-
#
|
|
431
|
+
# Create the private sync repo and scaffold it. You will be prompted for a
|
|
432
|
+
# repo name (default: claude-nomad-config). Pass --repo to skip the prompt.
|
|
477
433
|
$ nomad init
|
|
434
|
+
# or non-interactively:
|
|
435
|
+
$ nomad init --repo my-config
|
|
478
436
|
|
|
479
|
-
#
|
|
480
|
-
#
|
|
481
|
-
# your current ~/.claude/settings.json.
|
|
437
|
+
# If ~/.claude/ is already populated on this host, capture it as the starting
|
|
438
|
+
# point instead of an empty scaffold. Stages shared/ and writes
|
|
439
|
+
# hosts/<NOMAD_HOST>.json from your current ~/.claude/settings.json.
|
|
440
|
+
# Does NOT touch the originals.
|
|
482
441
|
$ nomad init --snapshot
|
|
483
442
|
```
|
|
484
443
|
|
|
@@ -487,6 +446,16 @@ safe no-op (it errors out naming the offender). `nomad pull` against an unscaffo
|
|
|
487
446
|
with `FATAL: repo not initialized; run 'nomad init' to scaffold` instead of silently leaving a
|
|
488
447
|
half-state.
|
|
489
448
|
|
|
449
|
+
Add a stable host label to your shell rc, then reload it:
|
|
450
|
+
|
|
451
|
+
```bash
|
|
452
|
+
export NOMAD_HOST=<your-host-label> # add to ~/.zshrc or ~/.bashrc
|
|
453
|
+
```
|
|
454
|
+
|
|
455
|
+
`NOMAD_HOST` overrides `os.hostname()`, which returns noisy values like `WINDOWS-I5NT6OH` on WSL or
|
|
456
|
+
`<name>.local` on macOS. Pick a clean label per machine (e.g., `wsl-laptop`, `macbook`,
|
|
457
|
+
`homelab-nuc`). `nomad doctor` reports the resolved host so you can confirm.
|
|
458
|
+
|
|
490
459
|
Edit `path-map.json` to add your logical projects (see [Path remapping](#path-remapping)), then:
|
|
491
460
|
|
|
492
461
|
```bash
|
|
@@ -505,6 +474,28 @@ If the destination host already has populated `~/.claude/{CLAUDE.md, agents/, ..
|
|
|
505
474
|
`nomad pull` will refuse to overwrite real files. See
|
|
506
475
|
[Migrating an existing ~/.claude/](#migrating-an-existing-claude) for the safe migration flow.
|
|
507
476
|
|
|
477
|
+
### Each additional host
|
|
478
|
+
|
|
479
|
+
```bash
|
|
480
|
+
# Install the CLI.
|
|
481
|
+
$ npm i -g claude-nomad
|
|
482
|
+
|
|
483
|
+
# Clone your private data repo.
|
|
484
|
+
$ gh repo clone <your-username>/claude-nomad-config ~/claude-nomad
|
|
485
|
+
# or with plain git:
|
|
486
|
+
$ git clone git@github.com:<your-username>/claude-nomad-config.git ~/claude-nomad
|
|
487
|
+
|
|
488
|
+
# Add to ~/.zshrc or ~/.bashrc, then reload.
|
|
489
|
+
export NOMAD_HOST=<your-host-label>
|
|
490
|
+
|
|
491
|
+
$ nomad pull # apply config to ~/.claude/
|
|
492
|
+
```
|
|
493
|
+
|
|
494
|
+
`npm i -g claude-nomad` puts a `nomad` binary on your PATH. What this means for you: there is no
|
|
495
|
+
compile step, no extra transpiler to install, and nothing is fetched from the network the first time
|
|
496
|
+
you run `nomad`, so the first run works offline. (The Node version floor and the `engine-strict`
|
|
497
|
+
caveat are in [Requirements](#requirements).)
|
|
498
|
+
|
|
508
499
|
## Migrating an existing ~/.claude/
|
|
509
500
|
|
|
510
501
|
If a host already has real files at `~/.claude/{CLAUDE.md, agents/, skills/, ...}` and you want to
|
|
@@ -536,88 +527,29 @@ Prefer an explicit tarball rollback and a confirmation prompt before any deletio
|
|
|
536
527
|
equivalent under `scripts/`: tar the `SHARED_LINKS` entries under `~/.claude/` first, copy into
|
|
537
528
|
`shared/`, prompt, then `nomad pull`. The auto-move path above is the recommended default.
|
|
538
529
|
|
|
539
|
-
## Upgrading the
|
|
530
|
+
## Upgrading the CLI
|
|
540
531
|
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
- **The `nomad` CLI binary** (what runs when you type `nomad`). If you installed it with
|
|
544
|
-
`npm i -g claude-nomad`, upgrade it with `npm update -g claude-nomad`. This refreshes only the
|
|
545
|
-
binary on your PATH; it does not touch anything inside your private `~/claude-nomad/` repo.
|
|
546
|
-
- **The synced tool files inside your private repo:** `src/`, `.gitleaks.toml` (the secret-scan
|
|
547
|
-
allowlist), and the `.github/workflows/` privacy gating. These were copied from the public repo at
|
|
548
|
-
bootstrap and then froze, so `npm update -g` does not refresh them. `nomad update`, run from
|
|
549
|
-
`~/claude-nomad/`, is what pulls newer versions of these files in. Topology-aware: detects vanilla
|
|
550
|
-
vs fork remotes, pulls or merges upstream, and re-runs `npm install` when `package-lock.json`
|
|
551
|
-
shifted.
|
|
552
|
-
|
|
553
|
-
Most people who followed the Quickstart need both: `npm update -g` for the binary, and an occasional
|
|
554
|
-
`nomad update` for the repo files (notably to receive `.gitleaks.toml` allowlist changes and any
|
|
555
|
-
update to the privacy gating itself). The mirror-push bootstrap leaves your repo with `origin` on
|
|
556
|
-
your private mirror and no `upstream` remote; that becomes the "fork" topology `nomad update`
|
|
557
|
-
expects once you add the upstream remote (the one-time `git remote add upstream ...` step is below).
|
|
558
|
-
|
|
559
|
-
Your private repo is not a fork, so GitHub's "Sync fork" UI doesn't apply. The shortcut on a
|
|
560
|
-
source-checkout host is:
|
|
532
|
+
`nomad update` updates the `nomad` binary from npm:
|
|
561
533
|
|
|
562
534
|
```bash
|
|
563
|
-
$ cd ~/claude-nomad
|
|
564
535
|
$ nomad update
|
|
565
536
|
```
|
|
566
537
|
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
- **fork** (`upstream` points at the public repo, `origin` points at your private mirror):
|
|
571
|
-
`git fetch upstream`, then (before merging) commit any whitelisted `shared/extras/` content that
|
|
572
|
-
is still untracked locally so an overlap with upstream becomes a normal file merge instead of an
|
|
573
|
-
untracked-overwrite abort, `git merge upstream/main`, then prompt before pushing the merge to
|
|
574
|
-
`origin/main`. Pass `--push-origin` to skip the prompt. When the merge is a no-op (HEAD unchanged,
|
|
575
|
-
nothing new to push) the prompt is skipped entirely and `nomad update` logs
|
|
576
|
-
`already in sync with origin/main`.
|
|
577
|
-
|
|
578
|
-
Pre-flight checks run before any mutation: `REPO_HOME` exists, the topology resolves to `vanilla` or
|
|
579
|
-
`fork`, the current branch is `main`, the working tree is clean (override with `--force`), and
|
|
580
|
-
`--push-origin` is rejected on vanilla topology.
|
|
581
|
-
|
|
582
|
-
After the merge or pull, `nomad update` re-runs `npm install` only when `package-lock.json` actually
|
|
583
|
-
shifted, commits the regenerated `package-lock.json` (fork topology) if the reinstall changed it,
|
|
584
|
-
then invokes `nomad doctor`. The trailing version-check is non-fatal: `✓` when local matches the
|
|
585
|
-
latest release, `⚠︎` when behind, an informational `ℹ︎ ... ahead of latest release` line when ahead
|
|
586
|
-
(e.g. a `-dev` build between releases), and silent on network failures.
|
|
587
|
-
|
|
588
|
-
Common cases:
|
|
589
|
-
|
|
590
|
-
```bash
|
|
591
|
-
$ nomad update # the usual path
|
|
592
|
-
$ nomad update --dry-run # detect topology + pre-flight, print would-be git commands only
|
|
593
|
-
$ nomad update --push-origin # fork topology: push merge to origin/main without prompting
|
|
594
|
-
$ nomad update --force # proceed past a dirty working tree
|
|
595
|
-
```
|
|
596
|
-
|
|
597
|
-
One-time setup if you're running a fork layout and don't have the `upstream` remote yet:
|
|
598
|
-
|
|
599
|
-
```bash
|
|
600
|
-
$ git remote add upstream git@github.com:funkadelic/claude-nomad.git
|
|
601
|
-
```
|
|
602
|
-
|
|
603
|
-
To pin to a specific release (`vX.Y.Z`, tagged by release-please) instead of tracking `main`, fetch
|
|
604
|
-
tags from the public repo and check out the tag (detached HEAD). On vanilla topology that's
|
|
605
|
-
`origin`; on fork topology that's `upstream` (the private mirror at `origin` does not accumulate
|
|
606
|
-
upstream release tags). Example: `git fetch upstream --tags && git switch --detach vX.Y.Z`
|
|
607
|
-
(substitute `origin` for vanilla; use `git checkout vX.Y.Z` on older Git).
|
|
538
|
+
What this means for you: it runs `npm update -g claude-nomad` and refreshes the binary on your PATH.
|
|
539
|
+
It does NOT pull your sync data; run `nomad pull` separately when you want to apply remote changes
|
|
540
|
+
to this host.
|
|
608
541
|
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
to the global binary, confirm `nomad --version` resolves to the npm install (`which nomad` should
|
|
612
|
-
point under your npm prefix's `bin/`), then delete the alias line from your shell rc.
|
|
542
|
+
`nomad doctor` reports when your local install is behind the latest npm release:
|
|
543
|
+
`⚠︎ claude-nomad: <local> -> <latest> (run nomad update)`.
|
|
613
544
|
|
|
614
545
|
## Commands
|
|
615
546
|
|
|
616
547
|
| Command | Description |
|
|
617
548
|
| -------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
618
|
-
| `nomad init` |
|
|
549
|
+
| `nomad init` | Create a private GitHub repo via `gh`, wire it as `origin`, disable Actions, scaffold `shared/`, `hosts/`, `path-map.json`, and push. Prompts for a repo name (default: `claude-nomad-config`). `gh` must be installed and authenticated; exits with FATAL otherwise. Refuses to clobber existing scaffold. See [Privacy by default](#privacy-by-default). |
|
|
550
|
+
| `nomad init --repo <name>` | Non-interactive: use `<name>` as the private repo name without prompting. Useful in scripts. |
|
|
619
551
|
| `nomad init --snapshot` | Overlay current host's `~/.claude/` into `shared/` and write `~/.claude/settings.json` verbatim into `hosts/<NOMAD_HOST>.json`. Originals not modified. Same auto-disable behavior as `nomad init`. |
|
|
620
|
-
| `nomad init --keep-actions` | Skip the
|
|
552
|
+
| `nomad init --keep-actions` | Skip the Actions-disable step. Combinable with `--snapshot` and `--repo`. Use when an org policy already governs Actions, or you intentionally want CI on the private repo. |
|
|
621
553
|
| `nomad pull` | `git pull --rebase --autostash`, apply symlinks, regenerate `settings.json`, remap session paths, and pull opted-in per-project extras. Errors out if scaffold missing. |
|
|
622
554
|
| `nomad pull --dry-run` | Network-aware preview: acquire lock + `git pull --rebase`, print planned changes (symlink moves, `settings.json` diff, transcript overwrites), exit without writing. |
|
|
623
555
|
| `nomad diff` | Offline, lockless twin of `pull --dry-run`. No network, no lock. Works against the current local repo state. |
|
|
@@ -630,7 +562,7 @@ point under your npm prefix's `bin/`), then delete the alias line from your shel
|
|
|
630
562
|
| `nomad redact <session-id>` | Rewrite the secret span in the local source transcript for a session, backed up to `~/.cache/claude-nomad/backup/`. Refuses to touch a session that was modified recently (potential active session). Safe to re-run. See [`nomad redact <session-id>`](#nomad-redact-session-id). |
|
|
631
563
|
| `nomad redact --rule <id>` | Limit redaction to findings of one gitleaks rule id only. |
|
|
632
564
|
| `nomad redact --dry-run` | Show what `nomad redact` would change without writing anything. |
|
|
633
|
-
| `nomad update` |
|
|
565
|
+
| `nomad update` | Update the `nomad` CLI binary from npm (`npm update -g claude-nomad`). Does NOT pull your sync data; run `nomad pull` separately for that. See [Upgrading the CLI](#upgrading-the-cli). |
|
|
634
566
|
| `nomad doctor` | Read-only health check. Each line carries a status glyph (`✓` pass, `✗` fail, `⚠︎` warn); any `✗` sets `process.exitCode = 1` (`⚠︎` does not). Includes an offline-tolerant release-version staleness check, a Hook targets check that fails (`✗`, exit 1) when `settings.json` references a hook command whose script under `~/.claude/` is missing on this host, plus two `⚠︎`-only drift checks: gitleaks version drift and, on a private GitHub mirror, re-enabled Actions. |
|
|
635
567
|
| `nomad doctor --resume-cmd <id>` | Print a host-local `cd ... && claude --resume <id>` line for a session (see [Cross-OS resume](#cross-os-resume)). |
|
|
636
568
|
| `nomad doctor --check-shared` | Read-only gitleaks preflight: stages the session transcripts a `push` would publish into a temp tree and scans them, failing (`✗`, exit 1) per affected session with rotate-and-scrub guidance. Skips with a `⚠︎` when gitleaks is not on PATH. See [Recovery flow: gitleaks FATAL on a session JSONL](#recovery-flow-gitleaks-fatal-on-a-session-jsonl). |
|
|
@@ -852,7 +784,8 @@ Two branches from here:
|
|
|
852
784
|
|
|
853
785
|
2. **False positive.** Add an allowlist regex to `.gitleaks.toml` at the repo root that matches the
|
|
854
786
|
noise pattern but not real-secret formats, commit it, then re-run `nomad push`. The new allowlist
|
|
855
|
-
propagates to
|
|
787
|
+
propagates to other hosts when they run `nomad update` (CLI upgrade) or when you push the updated
|
|
788
|
+
file to your data repo.
|
|
856
789
|
|
|
857
790
|
`nomad drop-session` only acts on the staged tree of `~/claude-nomad/`. Active Claude Code sessions
|
|
858
791
|
writing to the local file are not disturbed.
|
|
@@ -929,17 +862,64 @@ regexes = [
|
|
|
929
862
|
]
|
|
930
863
|
```
|
|
931
864
|
|
|
932
|
-
File location: `.gitleaks.toml`
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
865
|
+
File location: `.gitleaks.toml` ships bundled with the CLI binary. At runtime both `probeGitleaks`
|
|
866
|
+
(in `src/push-checks.ts`) and `runGitleaksScan` (in `src/push-gitleaks.ts`) try
|
|
867
|
+
`<REPO_HOME>/.gitleaks.toml` first and fall back to the package-bundled copy when the repo-level
|
|
868
|
+
file is absent. So when you have no repo-level copy the allowlist tracks the installed binary, and
|
|
869
|
+
running `nomad update` (to get the latest CLI) is enough to receive allowlist updates. If you do
|
|
870
|
+
place a `<REPO_HOME>/.gitleaks.toml`, it takes precedence and `nomad update` will not change it; you
|
|
871
|
+
maintain that file yourself.
|
|
872
|
+
|
|
873
|
+
#### Customizing the allowlist with an overlay
|
|
874
|
+
|
|
875
|
+
What this means for you: if you only want to allow a couple of extra patterns of your own (say, an
|
|
876
|
+
internal tool that emits a structured token that keeps tripping the scan), you do not have to copy
|
|
877
|
+
the whole bundled allowlist into your sync repo and keep it in step by hand. Instead, drop a small
|
|
878
|
+
`<REPO_HOME>/.gitleaks.overlay.toml` containing only your extra `[[allowlists]]` tables (and
|
|
879
|
+
optionally `[[rules]]`). nomad layers your entries on top of the bundled allowlist at scan time, so
|
|
880
|
+
the shipped Sonar / gitleaks / npm-audit / coverage noise allows stay in effect, the gitleaks
|
|
881
|
+
default ruleset stays in effect, and your additions are appended to all of them.
|
|
882
|
+
|
|
883
|
+
Why this is better than a full `.gitleaks.toml`: a full repo-level `.gitleaks.toml` replaces the
|
|
884
|
+
bundled allowlist outright, so the shipped noise allows are lost and `nomad update` can no longer
|
|
885
|
+
refresh them (you own that file). The overlay is additive instead: it never drops the bundled base,
|
|
886
|
+
and because the base still ships with the CLI, `nomad update` keeps the base current while your
|
|
887
|
+
overlay rides on top.
|
|
888
|
+
|
|
889
|
+
How it works, briefly: on `nomad push`, when the overlay is present, nomad generates a throwaway
|
|
890
|
+
config that extends the bundled `.gitleaks.toml` (which itself extends the gitleaks default),
|
|
891
|
+
appends your overlay body, scans with that combined config, then deletes the throwaway file. The
|
|
892
|
+
merge is gitleaks' own `[extend]` append, so your allowlist entries add to the shipped and default
|
|
893
|
+
ones rather than replacing them.
|
|
894
|
+
|
|
895
|
+
Two rules to keep in mind:
|
|
896
|
+
|
|
897
|
+
- Your overlay must NOT contain its own `[extend]` block. nomad writes the `[extend]` line for you;
|
|
898
|
+
if the overlay includes one, the push aborts with a clear error rather than scanning with a config
|
|
899
|
+
you did not intend.
|
|
900
|
+
- If you keep BOTH a full `<REPO_HOME>/.gitleaks.toml` AND an overlay, the full `.gitleaks.toml`
|
|
901
|
+
wins and the overlay is ignored (a full repo toml means you have taken complete manual control).
|
|
902
|
+
Pick one approach: the overlay for additive tweaks, or a full `.gitleaks.toml` for total control.
|
|
903
|
+
|
|
904
|
+
Example `<REPO_HOME>/.gitleaks.overlay.toml` (note: no `[extend]` block):
|
|
905
|
+
|
|
906
|
+
```toml
|
|
907
|
+
[[allowlists]]
|
|
908
|
+
description = "my-org: internal build-token noise"
|
|
909
|
+
regexes = [
|
|
910
|
+
'''BUILDTOK-[A-Za-z0-9]{24}''',
|
|
911
|
+
]
|
|
912
|
+
```
|
|
913
|
+
|
|
914
|
+
The overlay file is push-allowed (it is an exact-name entry in `PUSH_ALLOWED_STATIC` in
|
|
915
|
+
`src/config.ts`, alongside `.gitleaksignore`), so you can commit `.gitleaks.overlay.toml` to your
|
|
916
|
+
sync repo and it travels to your other hosts on the next `nomad pull`.
|
|
937
917
|
|
|
938
918
|
Editing: amend `.gitleaks.toml` in this repo, open a PR, and merge to `main`. Use TOML literal
|
|
939
919
|
strings (triple single quotes, `'''regex'''`) for new regex entries so backslashes do not need
|
|
940
920
|
escaping. Verify the new pattern does not match real-secret formats (`ghp_<36>`, `sk_live_*`,
|
|
941
|
-
`xoxb-*`, `AKIA[A-Z0-9]{16}`, etc.) before merging. The
|
|
942
|
-
|
|
921
|
+
`xoxb-*`, `AKIA[A-Z0-9]{16}`, etc.) before merging. The allowlist ships with the binary, so
|
|
922
|
+
`nomad update` on each host picks up the new file.
|
|
943
923
|
|
|
944
924
|
## Cross-OS resume
|
|
945
925
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "claude-nomad",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.34.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Sync Claude Code config (~/.claude/) across machines via a private Git repo, with path remapping and per-host settings overrides.",
|
|
6
6
|
"keywords": [
|
|
@@ -33,9 +33,9 @@
|
|
|
33
33
|
"node": ">=22.22.1"
|
|
34
34
|
},
|
|
35
35
|
"scripts": {
|
|
36
|
-
"pull": "
|
|
37
|
-
"push": "
|
|
38
|
-
"doctor": "
|
|
36
|
+
"pull": "node src/nomad.ts pull",
|
|
37
|
+
"push": "node src/nomad.ts push",
|
|
38
|
+
"doctor": "node src/nomad.ts doctor",
|
|
39
39
|
"update": "bash scripts/update.sh",
|
|
40
40
|
"test": "vitest run",
|
|
41
41
|
"coverage": "vitest run --coverage",
|
|
@@ -81,7 +81,6 @@
|
|
|
81
81
|
},
|
|
82
82
|
"dependencies": {
|
|
83
83
|
"diff": "^9.0.0",
|
|
84
|
-
"picocolors": "^1.1.1"
|
|
85
|
-
"tsx": "^4.22.2"
|
|
84
|
+
"picocolors": "^1.1.1"
|
|
86
85
|
}
|
|
87
86
|
}
|