repo-nexus 0.3.3 → 0.3.4

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/README.md CHANGED
@@ -54,7 +54,7 @@ A **simple, lightweight companion tool** for multi-repo workflows. It links mult
54
54
 
55
55
  ```
56
56
  ┌─────────────────────────────────────────────────────────────┐
57
- │ Repo Nexus Workspace Root │
57
+ │ Repo Nexus Workspace Root │
58
58
  │ │
59
59
  │ my-workspace/ │
60
60
  │ repos/ │
@@ -214,20 +214,22 @@ The `karpathy-llm` plugin packages Andrej Karpathy's verified LLM agent design p
214
214
  * **Autonomous Karpathy LLM Wiki Knowledge Architecture:**
215
215
  * **Intake (`/raw/`):** Append-only intake for unmodified source documents.
216
216
  * **Curated Knowledge Base (`/wiki/`):** Interlinked atomic markdown pages with typed YAML frontmatter relations (`sources`, `related`, `extends`, `contradicts`, `mentioned_in`).
217
- * **Control Index (`/wiki/index.md`):** Master navigation index with `lint_trigger: enabled|disabled` toggle.
217
+ * **Navigation Index (`/wiki/index.md`):** Master categorized navigation index.
218
218
  * **Rolling Context (`/wiki/hot.md`):** ~500-word quick-orient context cache for AI agents.
219
219
  * **Operation Log (`/wiki/_log.md`):** Append-only audit trail of ingest and lint operations.
220
- * **Session Counter (`.rnex/.lint_trigger_counter`):** Machine-local state tracking session activity (gitignored).
221
- * **Autonomous Lint Trigger (`.rnex/scripts/wiki-lint-trigger.sh`):** Session counter and maintenance alerts on session 1 and every 15 sessions.
222
220
  * **Standardized Workflows (`.rnex/workflows/`):**
223
221
  * `wiki-ingest.md`: 8-step protocol decomposing raw source documents into 5–25 atomic wiki pages.
224
222
  * `wiki-lint.md`: 10-step protocol validating paths, recomputing `mentioned_in`, removing orphans, resolving contradictions, identifying gaps, suggesting source candidates, and rebuilding indexes.
225
223
 
226
224
  ---
227
225
 
228
- ## Workspace Configuration (`rnex.yaml`)
226
+ ## Two-Level Configuration
229
227
 
230
- The configuration file defines repo symlink directory, enabled plugins, and registered repositories:
228
+ Repo Nexus supports a two-level configuration model:
229
+ 1. **Repo Config (`rnex.yaml`):** Shared manifest committed to git. Tracks member repo names, default settings, and active plugins.
230
+ 2. **Local Config (`.local.rnex.yaml`):** Machine-specific file ignored in `.gitignore`. Overrides or provides member repo paths on each developer's workstation.
231
+
232
+ ### Repo Configuration (`rnex.yaml`)
231
233
 
232
234
  ```yaml
233
235
  # Directory for repository symlinks (relative or absolute)
@@ -235,17 +237,15 @@ repos_dir: ./repos
235
237
 
236
238
  # Workspace plugins
237
239
  plugins:
238
- karpathy-llm:
239
- lint_trigger_enabled: true
240
+ karpathy-llm: {}
240
241
 
241
242
  # Member repositories
242
243
  repos:
243
244
  backend:
244
- path: /Users/dev/code/backend-api
245
245
  scope: visible
246
246
  rnex_dir: true # default: true (creates repos/backend/.rnex/)
247
247
  frontend:
248
- path: ../web-app
248
+ path: ../web-app # optional default relative path
249
249
  scope: visible
250
250
  rnex_dir: true
251
251
  analytics:
@@ -254,6 +254,14 @@ repos:
254
254
  rnex_dir: false # disabled: leaves analytics repo 100% untouched
255
255
  ```
256
256
 
257
+ ### Local Configuration (`.local.rnex.yaml`)
258
+
259
+ ```yaml
260
+ repos:
261
+ backend:
262
+ path: /Users/alice/projects/backend-api
263
+ ```
264
+
257
265
  > See [`docs/rnex.example.yaml`](docs/rnex.example.yaml) for a comprehensive example with all options.
258
266
  > For common questions and architecture details, see the [Frequently Asked Questions (FAQ)](docs/FAQ.md).
259
267
 
@@ -1,7 +1,13 @@
1
1
  # ==============================================================================
2
2
  # rnex.yaml — Repo Nexus Workspace Configuration (Full Example)
3
3
  # ==============================================================================
4
- # This file is the central manifest for a Repo Nexus workspace.
4
+ # This file is the central team manifest for a Repo Nexus workspace (committed to git).
5
+ #
6
+ # TWO-LEVEL CONFIGURATION:
7
+ # 1. Repo Config (rnex.yaml): Shared across team, tracks member repos, plugins.
8
+ # 2. Local Config (.local.rnex.yaml): Machine-specific (gitignored), overrides/provides
9
+ # local member repo paths and developer-specific plugin settings.
10
+ #
5
11
  # Place it in your workspace root directory and run `rnex sync` to apply.
6
12
  #
7
13
  # For more information: https://github.com/nu-nenoi/repo-nexus
@@ -37,8 +43,7 @@ repos_dir: ./repos
37
43
  # Local / custom plugins can also be placed in .rnex/plugins/<name>/
38
44
 
39
45
  plugins:
40
- # karpathy-llm:
41
- # lint_trigger_enabled: true
46
+ # karpathy-llm: {}
42
47
 
43
48
  # ------------------------------------------------------------------------------
44
49
  # repos — Member repositories managed by Repo Nexus
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "repo-nexus",
3
- "version": "0.3.3",
3
+ "version": "0.3.4",
4
4
  "description": "Lightweight, zero-dependency companion tool for multi-repo workspaces and shared AI context via symlinks (no git submodules)",
5
5
  "bin": {
6
6
  "repo-nexus": "rnex",
package/rnex CHANGED
@@ -8,6 +8,7 @@
8
8
  set -e
9
9
 
10
10
  RNEX_CONFIG_FILE="rnex.yaml"
11
+ RNEX_LOCAL_CONFIG_FILE=".local.rnex.yaml"
11
12
 
12
13
  # ---- Terminal Colours (auto-detected) -------------------------------------
13
14
 
@@ -92,17 +93,17 @@ RNEX_VERSION="$(resolve_version)"
92
93
 
93
94
  # ---- Workspace Detection (Context-Aware) ----------------------------------
94
95
 
95
- # Search for rnex.yaml in current directory or parent directories
96
+ # Search for rnex.yaml or .rnex.yaml in current directory or parent directories
96
97
  find_workspace_dir() {
97
98
  _curr="$(pwd -P 2>/dev/null || pwd)"
98
99
  while [ -n "$_curr" ] && [ "$_curr" != "/" ]; do
99
- if [ -f "$_curr/$RNEX_CONFIG_FILE" ]; then
100
+ if [ -f "$_curr/$RNEX_CONFIG_FILE" ] || [ -f "$_curr/.rnex.yaml" ]; then
100
101
  printf '%s' "$_curr"
101
102
  return 0
102
103
  fi
103
104
  _curr="$(dirname "$_curr")"
104
105
  done
105
- if [ -f "/$RNEX_CONFIG_FILE" ]; then
106
+ if [ -f "/$RNEX_CONFIG_FILE" ] || [ -f "/.rnex.yaml" ]; then
106
107
  printf '/'
107
108
  return 0
108
109
  fi
@@ -118,6 +119,7 @@ require_workspace() {
118
119
  fi
119
120
  NEXUS_DIR="$(cd -P "$(dirname "$_cfg_path")" 2>/dev/null && pwd -P)"
120
121
  WORKSPACE_YAML="$_cfg_path"
122
+ _init_local_yaml
121
123
  _load_repos_dir
122
124
  log_info "Using workspace at ${_BOLD}$NEXUS_DIR${_NC} ${_DIM}(via config: $WORKSPACE_YAML)${_NC}"
123
125
  return 0
@@ -136,16 +138,36 @@ require_workspace() {
136
138
  fi
137
139
 
138
140
  NEXUS_DIR="$_found_dir"
139
- WORKSPACE_YAML="$NEXUS_DIR/$RNEX_CONFIG_FILE"
141
+ if [ -f "$NEXUS_DIR/$RNEX_CONFIG_FILE" ]; then
142
+ WORKSPACE_YAML="$NEXUS_DIR/$RNEX_CONFIG_FILE"
143
+ elif [ -f "$NEXUS_DIR/.rnex.yaml" ]; then
144
+ WORKSPACE_YAML="$NEXUS_DIR/.rnex.yaml"
145
+ else
146
+ WORKSPACE_YAML="$NEXUS_DIR/$RNEX_CONFIG_FILE"
147
+ fi
148
+ _init_local_yaml
140
149
  _load_repos_dir
141
150
 
142
- log_info "Using workspace at ${_BOLD}$NEXUS_DIR${_NC} ${_DIM}($RNEX_CONFIG_FILE found)${_NC}"
151
+ log_info "Using workspace at ${_BOLD}$NEXUS_DIR${_NC} ${_DIM}($(basename "$WORKSPACE_YAML") found)${_NC}"
152
+ }
153
+
154
+ _init_local_yaml() {
155
+ if [ -f "$NEXUS_DIR/$RNEX_LOCAL_CONFIG_FILE" ]; then
156
+ WORKSPACE_LOCAL_YAML="$NEXUS_DIR/$RNEX_LOCAL_CONFIG_FILE"
157
+ elif [ -f "$NEXUS_DIR/.rnex.local.yaml" ]; then
158
+ WORKSPACE_LOCAL_YAML="$NEXUS_DIR/.rnex.local.yaml"
159
+ else
160
+ WORKSPACE_LOCAL_YAML="$NEXUS_DIR/$RNEX_LOCAL_CONFIG_FILE"
161
+ fi
143
162
  }
144
163
 
145
- # Parse repos_dir from config, default to ./repos
164
+ # Parse repos_dir from config, check local first then repo, default to ./repos
146
165
  _load_repos_dir() {
147
166
  _rd=""
148
- if [ -f "$WORKSPACE_YAML" ]; then
167
+ if [ -f "$WORKSPACE_LOCAL_YAML" ]; then
168
+ _rd="$(awk '/^repos_dir:/ { sub(/^repos_dir:[ ]*/, ""); sub(/[ ]*#.*/, ""); print }' "$WORKSPACE_LOCAL_YAML")"
169
+ fi
170
+ if [ -z "$_rd" ] && [ -f "$WORKSPACE_YAML" ]; then
149
171
  _rd="$(awk '/^repos_dir:/ { sub(/^repos_dir:[ ]*/, ""); sub(/[ ]*#.*/, ""); print }' "$WORKSPACE_YAML")"
150
172
  fi
151
173
  _rd="${_rd:-./repos}"
@@ -158,9 +180,10 @@ _load_repos_dir() {
158
180
  # ---- YAML Parser / Manipulator (for rnex.yaml) ----------------------------
159
181
 
160
182
 
161
- # Parse list of plugins from rnex.yaml (supports both mapping and list formats)
162
- yaml_list_plugins() {
163
- [ -f "$WORKSPACE_YAML" ] || return 0
183
+ # Parse list of plugins from a config file
184
+ _yaml_list_plugins_from_file() {
185
+ _f="$1"
186
+ [ -f "$_f" ] || return 0
164
187
  awk '
165
188
  /^plugins:[ ]*$/ || /^plugins:[ ]*#/ { p=1; next }
166
189
  p && /^[^ #]/ { exit }
@@ -189,13 +212,21 @@ yaml_list_plugins() {
189
212
  if (length(line) > 0) print line
190
213
  next
191
214
  }
192
- ' "$WORKSPACE_YAML"
215
+ ' "$_f"
193
216
  }
194
217
 
195
- # Get a configuration field value for a plugin under plugins.<plugin>.<field>
196
- yaml_plugin_get() {
197
- _plugin="$1"; _field="$2"
198
- [ -f "$WORKSPACE_YAML" ] || return 0
218
+ # Parse list of plugins merged from repo and local configs
219
+ yaml_list_plugins() {
220
+ {
221
+ _yaml_list_plugins_from_file "$WORKSPACE_YAML"
222
+ _yaml_list_plugins_from_file "$WORKSPACE_LOCAL_YAML"
223
+ } | awk '!seen[$0]++'
224
+ }
225
+
226
+ # Get a configuration field value for a plugin from a single file
227
+ _yaml_plugin_get_from_file() {
228
+ _f="$1"; _plugin="$2"; _field="$3"
229
+ [ -f "$_f" ] || return 0
199
230
  awk -v plugin="$_plugin" -v field="$_field" '
200
231
  /^plugins:[ ]*$/ || /^plugins:[ ]*#/ { in_plugins=1; next }
201
232
  in_plugins && /^[^ #]/ { in_plugins=0 }
@@ -212,7 +243,53 @@ yaml_plugin_get() {
212
243
  }
213
244
  }
214
245
  in_target && !/^ / && !/^[ ]*#/ { in_target=0 }
215
- ' "$WORKSPACE_YAML"
246
+ ' "$_f"
247
+ }
248
+
249
+ # Get a configuration field value for a plugin (local overrides repo config)
250
+ yaml_plugin_get() {
251
+ _plugin="$1"; _field="$2"
252
+ _val="$(_yaml_plugin_get_from_file "$WORKSPACE_LOCAL_YAML" "$_plugin" "$_field")"
253
+ if [ -n "$_val" ]; then
254
+ printf '%s' "$_val"
255
+ return 0
256
+ fi
257
+ _yaml_plugin_get_from_file "$WORKSPACE_YAML" "$_plugin" "$_field"
258
+ }
259
+
260
+ # List all configuration fields for a plugin with their source annotation
261
+ yaml_plugin_list_config() {
262
+ _plugin="$1"
263
+ if [ -f "$WORKSPACE_LOCAL_YAML" ]; then
264
+ awk -v plugin="$_plugin" '
265
+ /^plugins:[ ]*$/ || /^plugins:[ ]*#/ { in_p=1; next }
266
+ in_p && /^[^ #]/ { in_p=0 }
267
+ in_p && match($0, "^ " plugin ":[ ]*") { in_target=1; next }
268
+ in_target && /^ [a-zA-Z0-9_.-]+:[ ]*/ {
269
+ line = $0
270
+ sub(/^[ ]*/, "", line)
271
+ sub(/[ ]*#.*$/, "", line)
272
+ print line " (from local config)"
273
+ next
274
+ }
275
+ in_target && !/^ / && !/^[ ]*#/ { in_target=0 }
276
+ ' "$WORKSPACE_LOCAL_YAML"
277
+ fi
278
+ if [ -f "$WORKSPACE_YAML" ]; then
279
+ awk -v plugin="$_plugin" '
280
+ /^plugins:[ ]*$/ || /^plugins:[ ]*#/ { in_p=1; next }
281
+ in_p && /^[^ #]/ { in_p=0 }
282
+ in_p && match($0, "^ " plugin ":[ ]*") { in_target=1; next }
283
+ in_target && /^ [a-zA-Z0-9_.-]+:[ ]*/ {
284
+ line = $0
285
+ sub(/^[ ]*/, "", line)
286
+ sub(/[ ]*#.*$/, "", line)
287
+ print line
288
+ next
289
+ }
290
+ in_target && !/^ / && !/^[ ]*#/ { in_target=0 }
291
+ ' "$WORKSPACE_YAML"
292
+ fi
216
293
  }
217
294
 
218
295
  yaml_has_plugin() {
@@ -226,31 +303,20 @@ yaml_enable_plugin() {
226
303
  printf '\nplugins:\n' >> "$WORKSPACE_YAML"
227
304
  fi
228
305
  _tmp="$(mktemp)"
229
- if [ "$_name" = "karpathy-llm" ]; then
230
- awk -v name="$_name" '
231
- /^plugins:[ ]*$/ || /^plugins:[ ]*#/ {
232
- print
233
- printf " %s:\n lint_trigger_enabled: true\n", name
234
- added=1
235
- next
236
- }
237
- { print }
238
- ' "$WORKSPACE_YAML" > "$_tmp" && mv "$_tmp" "$WORKSPACE_YAML"
239
- else
240
- awk -v name="$_name" '
241
- /^plugins:[ ]*$/ || /^plugins:[ ]*#/ {
242
- print
243
- printf " %s: {}\n", name
244
- added=1
245
- next
246
- }
247
- { print }
248
- ' "$WORKSPACE_YAML" > "$_tmp" && mv "$_tmp" "$WORKSPACE_YAML"
249
- fi
306
+ awk -v name="$_name" '
307
+ /^plugins:[ ]*$/ || /^plugins:[ ]*#/ {
308
+ print
309
+ printf " %s: {}\n", name
310
+ added=1
311
+ next
312
+ }
313
+ { print }
314
+ ' "$WORKSPACE_YAML" > "$_tmp" && mv "$_tmp" "$WORKSPACE_YAML"
250
315
  }
251
316
 
252
- yaml_disable_plugin() {
253
- _name="$1"
317
+ _yaml_disable_plugin_in_file() {
318
+ _file="$1"; _name="$2"
319
+ [ -f "$_file" ] || return 0
254
320
  _tmp="$(mktemp)"
255
321
  awk -v name="$_name" '
256
322
  /^plugins:[ ]*$/ || /^plugins:[ ]*#/ { in_plugins=1; print; next }
@@ -260,35 +326,85 @@ yaml_disable_plugin() {
260
326
  in_target && !/^ / { in_target=0 }
261
327
  in_plugins && $0 ~ ("^[ ]*-[ ]*" name "[ ]*($|#)") { next }
262
328
  { print }
263
- ' "$WORKSPACE_YAML" > "$_tmp" && mv "$_tmp" "$WORKSPACE_YAML"
329
+ ' "$_file" > "$_tmp" && mv "$_tmp" "$_file"
264
330
  }
265
331
 
332
+ yaml_disable_plugin() {
333
+ _name="$1"
334
+ _yaml_disable_plugin_in_file "$WORKSPACE_YAML" "$_name"
335
+ _yaml_disable_plugin_in_file "$WORKSPACE_LOCAL_YAML" "$_name"
336
+ }
266
337
 
267
- # Parse list of repos from rnex.yaml
268
- yaml_list_repos() {
269
- [ -f "$WORKSPACE_YAML" ] || return 0
270
- cat "$WORKSPACE_YAML" | awk '
271
- /^repos:/ { r=1; next }
338
+ # Parse list of repos from a single config file
339
+ _yaml_list_repos_from_file() {
340
+ _f="$1"
341
+ [ -f "$_f" ] || return 0
342
+ awk '
343
+ /^repos:[ ]*$/ || /^repos:[ ]*#/ { r=1; next }
272
344
  r && /^[^ #]/ { exit }
273
- r && /^ [a-zA-Z0-9_.-]+:[ ]*$/ {
274
- sub(/^ /, ""); sub(/:.*/, ""); print
345
+ r && /^ [a-zA-Z0-9_.-]+:[ ]*(#.*)?$/ {
346
+ line = $0
347
+ sub(/^[ ]*/, "", line)
348
+ sub(/:.*/, "", line)
349
+ gsub(/[[:space:]]/, "", line)
350
+ if (length(line) > 0) print line
275
351
  }
276
- '
352
+ ' "$_f"
277
353
  }
278
354
 
279
- # Get a field value for a repo
355
+ # Parse list of repos merged from repo and local configs (order preserved, deduplicated)
356
+ yaml_list_repos() {
357
+ {
358
+ _yaml_list_repos_from_file "$WORKSPACE_YAML"
359
+ _yaml_list_repos_from_file "$WORKSPACE_LOCAL_YAML"
360
+ } | awk '!seen[$0]++'
361
+ }
362
+
363
+ # Get a field value for a repo from a specific config file
364
+ _yaml_get_from_file() {
365
+ _f="$1"; _repo="$2"; _field="$3"
366
+ [ -f "$_f" ] || return 0
367
+ awk -v repo="$_repo" -v field="$_field" '
368
+ /^repos:[ ]*$/ || /^repos:[ ]*#/ { r=1; next }
369
+ r && /^[^ #]/ { r=0 }
370
+ r && match($0, "^ " repo ":[ ]*(#.*)?$") { in_target=1; next }
371
+ in_target && /^ [^ #]/ { in_target=0 }
372
+ in_target && match($0, "^ " field ":[ ]*") {
373
+ line = $0
374
+ sub("^ " field ":[ ]*", "", line)
375
+ sub(/[ ]*#.*$/, "", line)
376
+ gsub(/^["\x27]|["\x27]$/, "", line)
377
+ print line
378
+ exit
379
+ }
380
+ ' "$_f"
381
+ }
382
+
383
+ # Get a field value for a repo (local config overrides repo config)
280
384
  yaml_get() {
281
385
  _repo="$1"; _field="$2"
282
- [ -f "$WORKSPACE_YAML" ] || return 0
283
- cat "$WORKSPACE_YAML" | awk -v repo="$_repo" -v field="$_field" '
284
- /^repos:/ { r=1; next }
285
- r && /^[^ #]/ { exit }
286
- r && match($0, "^ " repo ":[ ]*$") { t=1; next }
287
- r && t && /^ [^ #]/ { exit }
288
- r && t && match($0, "^ " field ":") {
289
- sub(/^ [a-zA-Z0-9_.-]+:[ ]*/, ""); print
290
- }
291
- '
386
+ _val="$(_yaml_get_from_file "$WORKSPACE_LOCAL_YAML" "$_repo" "$_field")"
387
+ if [ -n "$_val" ]; then
388
+ printf '%s' "$_val"
389
+ return 0
390
+ fi
391
+ _yaml_get_from_file "$WORKSPACE_YAML" "$_repo" "$_field"
392
+ }
393
+
394
+ # Return where the repo path came from: "local", "repo", or "none"
395
+ yaml_repo_path_source() {
396
+ _repo="$1"
397
+ _lval="$(_yaml_get_from_file "$WORKSPACE_LOCAL_YAML" "$_repo" "path")"
398
+ if [ -n "$_lval" ]; then
399
+ printf 'local'
400
+ return 0
401
+ fi
402
+ _rval="$(_yaml_get_from_file "$WORKSPACE_YAML" "$_repo" "path")"
403
+ if [ -n "$_rval" ]; then
404
+ printf 'repo'
405
+ return 0
406
+ fi
407
+ printf 'none'
292
408
  }
293
409
 
294
410
  yaml_has_repo() {
@@ -297,7 +413,7 @@ yaml_has_repo() {
297
413
 
298
414
  yaml_add_repo() {
299
415
  _name="$1"; _path="$2"; _rnex_dir="${3:-true}"
300
- if ! grep -q '^repos:' "$WORKSPACE_YAML"; then
416
+ if ! grep -q '^repos:' "$WORKSPACE_YAML" 2>/dev/null; then
301
417
  printf '\nrepos:\n' >> "$WORKSPACE_YAML"
302
418
  fi
303
419
  _tmp="$(mktemp)"
@@ -312,8 +428,9 @@ yaml_add_repo() {
312
428
  ' "$WORKSPACE_YAML" > "$_tmp" && mv "$_tmp" "$WORKSPACE_YAML"
313
429
  }
314
430
 
315
- yaml_remove_repo() {
316
- _name="$1"
431
+ _yaml_remove_repo_from_file() {
432
+ _file="$1"; _name="$2"
433
+ [ -f "$_file" ] || return 0
317
434
  _tmp="$(mktemp)"
318
435
  awk -v name="$_name" '
319
436
  /^repos:/ { r=1; print; next }
@@ -322,11 +439,48 @@ yaml_remove_repo() {
322
439
  r && skip && /^ [^ #]/ { skip=0 }
323
440
  skip && /^ / { next }
324
441
  { print }
325
- ' "$WORKSPACE_YAML" > "$_tmp" && mv "$_tmp" "$WORKSPACE_YAML"
442
+ ' "$_file" > "$_tmp" && mv "$_tmp" "$_file"
326
443
  }
327
444
 
328
- yaml_set() {
329
- _repo="$1"; _field="$2"; _value="$3"
445
+ yaml_remove_repo() {
446
+ _name="$1"
447
+ _yaml_remove_repo_from_file "$WORKSPACE_YAML" "$_name"
448
+ _yaml_remove_repo_from_file "$WORKSPACE_LOCAL_YAML" "$_name"
449
+ }
450
+
451
+ _yaml_set_in_file() {
452
+ _file="$1"; _repo="$2"; _field="$3"; _value="$4"
453
+ if [ ! -f "$_file" ]; then
454
+ mkdir -p "$(dirname "$_file")"
455
+ printf 'repos:\n' > "$_file"
456
+ elif ! grep -q '^repos:' "$_file" 2>/dev/null; then
457
+ printf '\nrepos:\n' >> "$_file"
458
+ fi
459
+
460
+ if ! awk -v repo="$_repo" '
461
+ /^repos:[ ]*$/ || /^repos:[ ]*#/ { in_r=1; next }
462
+ in_r && /^[^ #]/ { in_r=0 }
463
+ in_r && match($0, "^ " repo ":[ ]*(#.*)?$") { found=1; exit }
464
+ END { exit !found }
465
+ ' "$_file" 2>/dev/null; then
466
+ _tmp="$(mktemp)"
467
+ awk -v repo="$_repo" -v field="$_field" -v value="$_value" '
468
+ /^repos:[ ]*$/ || /^repos:[ ]*#/ {
469
+ print
470
+ printf " %s:\n %s: %s\n", repo, field, value
471
+ added=1
472
+ next
473
+ }
474
+ { print }
475
+ END {
476
+ if (!added) {
477
+ printf "repos:\n %s:\n %s: %s\n", repo, field, value
478
+ }
479
+ }
480
+ ' "$_file" > "$_tmp" && mv "$_tmp" "$_file"
481
+ return 0
482
+ fi
483
+
330
484
  _tmp="$(mktemp)"
331
485
  awk -v repo="$_repo" -v field="$_field" -v value="$_value" '
332
486
  /^repos:/ { in_repos=1; print; next }
@@ -337,11 +491,7 @@ yaml_set() {
337
491
  }
338
492
  in_repos=0; in_target=0
339
493
  }
340
- in_repos && match($0, "^ " repo ":[ ]*$") {
341
- if (in_target && !field_set) {
342
- printf " %s: %s\n", field, value
343
- field_set=1
344
- }
494
+ in_repos && match($0, "^ " repo ":[ ]*(#.*)?$") {
345
495
  in_target=1; print; next
346
496
  }
347
497
  in_target && /^ [^ #]/ {
@@ -362,7 +512,28 @@ yaml_set() {
362
512
  printf " %s: %s\n", field, value
363
513
  }
364
514
  }
365
- ' "$WORKSPACE_YAML" > "$_tmp" && mv "$_tmp" "$WORKSPACE_YAML"
515
+ ' "$_file" > "$_tmp" && mv "$_tmp" "$_file"
516
+ }
517
+
518
+ yaml_set() {
519
+ _repo="$1"; _field="$2"; _value="$3"
520
+ _yaml_set_in_file "$WORKSPACE_YAML" "$_repo" "$_field" "$_value"
521
+ }
522
+
523
+ yaml_set_local() {
524
+ _repo="$1"; _field="$2"; _value="$3"
525
+ if [ ! -f "$WORKSPACE_LOCAL_YAML" ]; then
526
+ cat <<'EOF' > "$WORKSPACE_LOCAL_YAML"
527
+ # ==============================================================================
528
+ # .local.rnex.yaml — Repo Nexus Local Configuration (Machine-Specific)
529
+ # ==============================================================================
530
+ # This file is gitignored. Use it to specify local repository paths and
531
+ # custom local plugin overrides for this workstation.
532
+
533
+ repos:
534
+ EOF
535
+ fi
536
+ _yaml_set_in_file "$WORKSPACE_LOCAL_YAML" "$_repo" "$_field" "$_value"
366
537
  }
367
538
 
368
539
  # ---- Symlink & Member Repo Operations -------------------------------------
@@ -629,16 +800,6 @@ sync_plugins() {
629
800
  log_ok "Initialized template: $_d"
630
801
  fi
631
802
  done
632
-
633
- # Reconcile plugin configuration (e.g., lint_trigger_enabled for karpathy-llm)
634
- if [ "$_pname" = "karpathy-llm" ] && [ -f "$NEXUS_DIR/wiki/index.md" ]; then
635
- _lte="$(yaml_plugin_get "karpathy-llm" "lint_trigger_enabled")"
636
- if [ "$_lte" = "false" ]; then
637
- sed -i.bak 's/lint_trigger:[ ]*enabled/lint_trigger: disabled/' "$NEXUS_DIR/wiki/index.md" 2>/dev/null && rm -f "$NEXUS_DIR/wiki/index.md.bak"
638
- elif [ "$_lte" = "true" ]; then
639
- sed -i.bak 's/lint_trigger:[ ]*disabled/lint_trigger: enabled/' "$NEXUS_DIR/wiki/index.md" 2>/dev/null && rm -f "$NEXUS_DIR/wiki/index.md.bak"
640
- fi
641
- fi
642
803
  done
643
804
  }
644
805
 
@@ -791,6 +952,12 @@ YAML_EOF
791
952
  mkdir -p "$_target_dir/.rnex/rules"
792
953
  mkdir -p "$_target_dir/.rnex/instructions"
793
954
 
955
+ # ---- Ensure local config is gitignored -----------------------------------
956
+ _target_gi="$_target_dir/.gitignore"
957
+ if [ ! -f "$_target_gi" ] || ! grep -qF "$RNEX_LOCAL_CONFIG_FILE" "$_target_gi" 2>/dev/null; then
958
+ printf '\n# Local machine-specific configuration\n%s\n.rnex.local.yaml\n' "$RNEX_LOCAL_CONFIG_FILE" >> "$_target_gi"
959
+ fi
960
+
794
961
  if [ "$_config_created" -eq 1 ]; then
795
962
  printf '\n'
796
963
  log_ok "Initialized Repo Nexus workspace at ${_BOLD}$_target_dir${_NC}"
@@ -808,9 +975,11 @@ cmd_add() {
808
975
  _name=""
809
976
  _path=""
810
977
  _rnex_dir="true"
978
+ _is_local=0
811
979
 
812
980
  while [ $# -gt 0 ]; do
813
981
  case "$1" in
982
+ --local) _is_local=1 ;;
814
983
  --no-rnex-dir|--rnex-dir=false) _rnex_dir="false" ;;
815
984
  --rnex-dir|--rnex-dir=true) _rnex_dir="true" ;;
816
985
  -y|--yes) _assume="y" ;;
@@ -828,15 +997,39 @@ cmd_add() {
828
997
  shift
829
998
  done
830
999
 
831
- [ -n "$_name" ] || die "Usage: rnex add [--no-rnex-dir] <name> <path>"
832
- [ -n "$_path" ] || die "Usage: rnex add [--no-rnex-dir] <name> <path>"
833
-
834
- yaml_has_repo "$_name" && die "Repo '$_name' is already registered in $RNEX_CONFIG_FILE"
1000
+ [ -n "$_name" ] || die "Usage: rnex add [--local] [--no-rnex-dir] <name> <path>"
1001
+ [ -n "$_path" ] || die "Usage: rnex add [--local] [--no-rnex-dir] <name> <path>"
835
1002
 
836
1003
  _path="$(resolve_path "$_path")"
837
1004
  [ -d "$_path" ] || die "Directory does not exist: $_path"
838
1005
 
839
1006
  ensure_repos_dir
1007
+
1008
+ if [ "$_is_local" -eq 1 ]; then
1009
+ yaml_set_local "$_name" "path" "$_path"
1010
+ [ "$_rnex_dir" = "false" ] && yaml_set_local "$_name" "rnex_dir" "false"
1011
+ create_scope_link "$_name"
1012
+ sync_repo_rnex "$_name"
1013
+ printf '\n'
1014
+ log_ok "Registered local path for repo '${_name}' in $(basename "$WORKSPACE_LOCAL_YAML")"
1015
+ return 0
1016
+ fi
1017
+
1018
+ if grep -q "^ $_name:" "$WORKSPACE_YAML" 2>/dev/null; then
1019
+ _existing_path="$(_yaml_get_from_file "$WORKSPACE_YAML" "$_name" "path")"
1020
+ if [ -n "$_existing_path" ]; then
1021
+ die "Repo '$_name' is already registered in $(basename "$WORKSPACE_YAML")"
1022
+ else
1023
+ yaml_set "$_name" "path" "$_path"
1024
+ [ "$_rnex_dir" = "false" ] && yaml_set "$_name" "rnex_dir" "false"
1025
+ create_scope_link "$_name"
1026
+ sync_repo_rnex "$_name"
1027
+ printf '\n'
1028
+ log_ok "Updated repo '${_name}' path in $(basename "$WORKSPACE_YAML")"
1029
+ return 0
1030
+ fi
1031
+ fi
1032
+
840
1033
  yaml_add_repo "$_name" "$_path" "$_rnex_dir"
841
1034
  create_scope_link "$_name"
842
1035
  sync_repo_rnex "$_name"
@@ -879,18 +1072,20 @@ cmd_hide() {
879
1072
 
880
1073
  cmd_list() {
881
1074
  require_workspace
882
- printf '%b%-22s %-10s %-12s %s%b\n' "$_B" "NAME" "SCOPE" "RNEX_DIR" "PATH" "$_NC"
883
- printf '%-22s %-10s %-12s %s\n' "----" "-----" "--------" "----"
1075
+ printf '%b%-22s %-10s %-12s %-8s %s%b\n' "$_B" "NAME" "SCOPE" "RNEX_DIR" "CONFIG" "PATH" "$_NC"
1076
+ printf '%-22s %-10s %-12s %-8s %s\n' "----" "-----" "--------" "------" "----"
884
1077
  yaml_list_repos | while read -r _name; do
1078
+ [ -n "$_name" ] || continue
885
1079
  _scope="$(yaml_get "$_name" "scope")"
886
1080
  _path="$(yaml_get "$_name" "path")"
1081
+ _src="$(yaml_repo_path_source "$_name")"
887
1082
  if repo_rnex_dir_enabled "$_name"; then
888
1083
  _rd_str="enabled"
889
1084
  else
890
1085
  _rd_str="disabled"
891
1086
  fi
892
- printf '%-22s %-10s %-12s %s\n' \
893
- "$_name" "${_scope:-visible}" "$_rd_str" "$_path"
1087
+ printf '%-22s %-10s %-12s %-8s %s\n' \
1088
+ "$_name" "${_scope:-visible}" "$_rd_str" "${_src:-repo}" "${_path:-(not set)}"
894
1089
  done
895
1090
  }
896
1091
 
@@ -902,6 +1097,20 @@ cmd_status() {
902
1097
  printf '=%.0s' 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
903
1098
  printf '\n\n'
904
1099
 
1100
+ printf '%bConfiguration:%b\n' "$_BOLD" "$_NC"
1101
+ if [ -f "$WORKSPACE_YAML" ]; then
1102
+ printf ' %b●%b Repo Config: %s %b(loaded)%b\n' "$_G" "$_NC" "$WORKSPACE_YAML" "$_DIM" "$_NC"
1103
+ else
1104
+ printf ' %b✗%b Repo Config: %s %b(missing)%b\n' "$_R" "$_NC" "$WORKSPACE_YAML" "$_R" "$_NC"
1105
+ fi
1106
+ if [ -f "$WORKSPACE_LOCAL_YAML" ]; then
1107
+ printf ' %b●%b Local Config: %s %b(loaded, overrides repo config)%b\n' "$_G" "$_NC" "$WORKSPACE_LOCAL_YAML" "$_DIM" "$_NC"
1108
+ else
1109
+ printf ' %b○%b Local Config: %s %b(not found — using repo defaults)%b\n' "$_DIM" "$_NC" "$WORKSPACE_LOCAL_YAML" "$_DIM" "$_NC"
1110
+ fi
1111
+ printf ' %b●%b Repos Dir: %s\n' "$_DIM" "$_NC" "$REPOS_DIR"
1112
+ printf '\n'
1113
+
905
1114
  printf '%bWorkspace AI Context:%b\n' "$_BOLD" "$_NC"
906
1115
  if [ -e "$NEXUS_DIR/AGENTS.md" ]; then
907
1116
  printf ' %b✓%b %s\n' "$_G" "$_NC" "AGENTS.md"
@@ -925,26 +1134,45 @@ cmd_status() {
925
1134
  _ver="$(plugin_get_field "$_pdir" "version")"
926
1135
  _desc="$(plugin_get_field "$_pdir" "description")"
927
1136
  printf ' %b●%b %-18s %b(v%s)%b %s\n' "$_G" "$_NC" "$_pname" "$_DIM" "${_ver:-0.1.0}" "$_NC" "${_desc:+- $_desc}"
1137
+ _pcfg="$(yaml_plugin_list_config "$_pname")"
1138
+ if [ -n "$_pcfg" ]; then
1139
+ printf ' %bConfiguration:%b\n' "$_DIM" "$_NC"
1140
+ echo "$_pcfg" | while read -r _line; do
1141
+ [ -n "$_line" ] && printf ' %b- %s%b\n' "$_DIM" "$_line" "$_NC"
1142
+ done
1143
+ else
1144
+ printf ' %bConfiguration: (default)%b\n' "$_DIM" "$_NC"
1145
+ fi
928
1146
  else
929
1147
  printf ' %b✗%b %-18s %bMISSING%b\n' "$_R" "$_NC" "$_pname" "$_R" "$_NC"
1148
+ printf ' %b↳ [!] Issue: plugin declared in config but directory not found on disk%b\n' "$_R" "$_NC"
930
1149
  fi
931
1150
  done
932
1151
  fi
933
1152
  printf '\n'
934
1153
 
935
1154
  printf '%b%s%b\n' "$_BOLD" "Member Repositories:" "$_NC"
936
- if [ -z "$(yaml_list_repos)" ]; then
1155
+ _all_repos="$(yaml_list_repos)"
1156
+ if [ -z "$_all_repos" ]; then
937
1157
  printf ' %b%s%b\n' "$_DIM" "(No repositories registered yet. Use 'rnex add <name> <path>')" "$_NC"
938
1158
  else
939
- yaml_list_repos | while read -r _name; do
1159
+ echo "$_all_repos" | while read -r _name; do
1160
+ [ -n "$_name" ] || continue
940
1161
  _scope="$(yaml_get "$_name" "scope")"
941
1162
  _path="$(yaml_get "$_name" "path")"
1163
+ _src="$(yaml_repo_path_source "$_name")"
1164
+ _src_tag=""
1165
+ if [ "$_src" = "local" ]; then
1166
+ _src_tag=" ${_DIM}(via $(basename "$WORKSPACE_LOCAL_YAML"))${_NC}"
1167
+ elif [ "$_src" = "repo" ]; then
1168
+ _src_tag=" ${_DIM}(via $(basename "$WORKSPACE_YAML"))${_NC}"
1169
+ fi
1170
+
942
1171
  _link="$REPOS_DIR/$_name"
943
- _resolved_path="$(resolve_repo_path "$_path")"
944
1172
 
945
1173
  _rnex_tag=""
946
1174
  if repo_rnex_dir_enabled "$_name"; then
947
- if [ -d "$_resolved_path/.rnex" ]; then
1175
+ if [ -n "$_path" ] && [ -d "$(resolve_repo_path "$_path")/.rnex" ]; then
948
1176
  _rnex_tag=" ${_DIM}[.rnex ✓]${_NC}"
949
1177
  else
950
1178
  _rnex_tag=" ${_Y}[.rnex pending]${_NC}"
@@ -953,32 +1181,94 @@ cmd_status() {
953
1181
  _rnex_tag=" ${_DIM}[.rnex disabled]${_NC}"
954
1182
  fi
955
1183
 
1184
+ if [ -z "$_path" ]; then
1185
+ printf ' %b✗%b %-22s %bMISSING PATH%b%b\n' "$_R" "$_NC" "$_name" "$_R" "$_NC" "$_rnex_tag"
1186
+ printf ' %b↳ Suggestion: set path in %s or run '\''rnex add %s <path> --local'\''%b\n' \
1187
+ "$_Y" "$(basename "$WORKSPACE_LOCAL_YAML")" "$_name" "$_NC"
1188
+ continue
1189
+ fi
1190
+
1191
+ _resolved_path="$(resolve_repo_path "$_path")"
1192
+
1193
+ if [ ! -d "$_resolved_path" ]; then
1194
+ printf ' %b✗%b %-22s %bBROKEN PATH%b%b → %s%b\n' "$_R" "$_NC" "$_name" "$_R" "$_NC" "$_rnex_tag" "$_path" "$_src_tag"
1195
+ printf ' %b↳ Suggestion: update path in %s or run '\''rnex add %s <path> --local'\''%b\n' \
1196
+ "$_Y" "$(basename "$WORKSPACE_LOCAL_YAML")" "$_name" "$_NC"
1197
+ continue
1198
+ fi
1199
+
956
1200
  if [ "$_scope" = "hidden" ]; then
957
- printf ' %b○%b %-22s %bhidden%b%b\n' "$_Y" "$_NC" "$_name" "$_DIM" "$_NC" "$_rnex_tag"
1201
+ printf ' %b○%b %-22s %bhidden%b%b → %s%b\n' "$_Y" "$_NC" "$_name" "$_DIM" "$_NC" "$_rnex_tag" "$_path" "$_src_tag"
958
1202
  elif [ -L "$_link" ] && [ -d "$_link" ]; then
959
- printf ' %b●%b %-22s %bactive%b%b → %s\n' "$_G" "$_NC" "$_name" "$_G" "$_NC" "$_rnex_tag" "$_path"
1203
+ printf ' %b●%b %-22s %bactive%b%b → %s%b\n' "$_G" "$_NC" "$_name" "$_G" "$_NC" "$_rnex_tag" "$_path" "$_src_tag"
960
1204
  elif [ -L "$_link" ]; then
961
- printf ' %b✗%b %-22s %bBROKEN LINK%b%b → %s\n' "$_R" "$_NC" "$_name" "$_R" "$_NC" "$_rnex_tag" "$_path"
1205
+ printf ' %b✗%b %-22s %bBROKEN LINK%b%b → %s%b\n' "$_R" "$_NC" "$_name" "$_R" "$_NC" "$_rnex_tag" "$_path" "$_src_tag"
1206
+ printf ' %b↳ Suggestion: run '\''rnex sync'\'' to recreate scope link%b\n' "$_Y" "$_NC"
962
1207
  else
963
- printf ' %b✗%b %-22s %bMISSING LINK%b%b %s\n' "$_R" "$_NC" "$_name" "$_R" "$_NC" "$_rnex_tag" "(run 'rnex sync')"
1208
+ printf ' %b✗%b %-22s %bMISSING LINK%b%b → %s%b\n' "$_R" "$_NC" "$_name" "$_R" "$_NC" "$_rnex_tag" "$_path" "$_src_tag"
1209
+ printf ' %b↳ Suggestion: run '\''rnex sync'\'' to create scope link%b\n' "$_Y" "$_NC"
964
1210
  fi
965
1211
  done
966
1212
  fi
967
1213
 
968
1214
  printf '\n%bWorkspace: %s%b\n' "$_DIM" "$NEXUS_DIR" "$_NC"
969
1215
  printf '%bRepos Dir: %s%b\n' "$_DIM" "$REPOS_DIR" "$_NC"
970
- printf '%bConfig: %s%b\n\n' "$_DIM" "$WORKSPACE_YAML" "$_NC"
1216
+ printf '%bRepo Config: %s%b\n' "$_DIM" "$WORKSPACE_YAML" "$_NC"
1217
+ [ -f "$WORKSPACE_LOCAL_YAML" ] && printf '%bLocal Config:%s%b\n' "$_DIM" " $WORKSPACE_LOCAL_YAML" "$_NC"
1218
+ printf '\n'
971
1219
  }
972
1220
 
973
1221
  cmd_sync() {
974
1222
  require_workspace
975
1223
  ensure_repos_dir
976
1224
 
977
- log_info "Synchronizing workspace from $RNEX_CONFIG_FILE..."
1225
+ log_info "Synchronizing workspace from $(basename "$WORKSPACE_YAML")..."
978
1226
  sync_plugins
1227
+
979
1228
  yaml_list_repos | while read -r _name; do
1229
+ [ -n "$_name" ] || continue
1230
+ _raw_path="$(yaml_get "$_name" "path")"
980
1231
  _scope="$(yaml_get "$_name" "scope")"
981
1232
 
1233
+ if [ -z "$_raw_path" ]; then
1234
+ log_warn "Member repo '${_BOLD}$_name${_NC}' has NO path configured in $(basename "$WORKSPACE_YAML") or $(basename "$WORKSPACE_LOCAL_YAML")"
1235
+ _prompted_path=""
1236
+ if [ -t 0 ] && [ -t 1 ]; then
1237
+ printf '%b Enter local path for member repo %s%b (or press Enter to skip): ' "$_BOLD" "$_name" "$_NC"
1238
+ read -r _prompted_path || true
1239
+ fi
1240
+ if [ -n "$_prompted_path" ]; then
1241
+ _p_res="$(resolve_path "$_prompted_path")"
1242
+ if [ -d "$_p_res" ]; then
1243
+ yaml_set_local "$_name" "path" "$_prompted_path"
1244
+ log_ok "Saved local path for '$_name' to $(basename "$WORKSPACE_LOCAL_YAML")"
1245
+ _raw_path="$_prompted_path"
1246
+ else
1247
+ log_err "Directory does not exist: $_p_res"
1248
+ fi
1249
+ fi
1250
+ if [ -z "$_raw_path" ]; then
1251
+ log_dim "To provide your local path for '$_name', configure $(basename "$WORKSPACE_LOCAL_YAML"):"
1252
+ log_dim " repos:"
1253
+ log_dim " $_name:"
1254
+ log_dim " path: /path/to/$_name"
1255
+ log_dim "Or run: rnex add $_name /path/to/$_name --local"
1256
+ continue
1257
+ fi
1258
+ fi
1259
+
1260
+ _resolved_path="$(resolve_repo_path "$_raw_path")"
1261
+ if [ ! -d "$_resolved_path" ]; then
1262
+ log_warn "Member repo '${_BOLD}$_name${_NC}' path does not exist on disk: $_resolved_path"
1263
+ log_dim "To fix this path locally on your machine, configure $(basename "$WORKSPACE_LOCAL_YAML"):"
1264
+ log_dim " repos:"
1265
+ log_dim " $_name:"
1266
+ log_dim " path: /path/to/$_name"
1267
+ log_dim "Or run: rnex add $_name /correct/path/to/$_name --local"
1268
+ remove_scope_link "$_name" 2>/dev/null || true
1269
+ continue
1270
+ fi
1271
+
982
1272
  if [ "$_scope" = "hidden" ]; then
983
1273
  remove_scope_link "$_name"
984
1274
  else
@@ -1048,9 +1338,12 @@ cmd_plugin_info() {
1048
1338
  [ -n "$_home" ] && printf '%bHomepage:%b %s\n' "$_BOLD" "$_NC" "$_home"
1049
1339
  printf '%bLocation:%b %s\n' "$_BOLD" "$_NC" "$_pdir"
1050
1340
  if yaml_has_plugin "$_name"; then
1051
- _lte="$(yaml_plugin_get "$_name" "lint_trigger_enabled")"
1052
- if [ -n "$_lte" ]; then
1053
- printf '%bConfiguration:%b lint_trigger_enabled: %s\n' "$_BOLD" "$_NC" "$_lte"
1341
+ _cfg="$(yaml_plugin_list_config "$_name")"
1342
+ if [ -n "$_cfg" ]; then
1343
+ printf '%bConfiguration:%b\n' "$_BOLD" "$_NC"
1344
+ echo "$_cfg" | while read -r _cline; do
1345
+ [ -n "$_cline" ] && printf ' %s\n' "$_cline"
1346
+ done
1054
1347
  fi
1055
1348
  fi
1056
1349
 
@@ -1099,7 +1392,7 @@ cmd_plugin_enable() {
1099
1392
  [ -n "$_name" ] || _name="$_pname"
1100
1393
 
1101
1394
  yaml_enable_plugin "$_name"
1102
- log_ok "Plugin '$_name' enabled in $RNEX_CONFIG_FILE"
1395
+ log_ok "Plugin '$_name' enabled in $(basename "$WORKSPACE_YAML")"
1103
1396
 
1104
1397
  # Link rules and workflows into workspace root
1105
1398
  plugin_list_rules "$_pdir" | while read -r _item; do
@@ -1137,13 +1430,11 @@ cmd_plugin_enable() {
1137
1430
  fi
1138
1431
  done
1139
1432
 
1140
- # Ensure machine-local state files (like .rnex/.lint_trigger_counter) are gitignored
1433
+ # Ensure local machine-specific config is gitignored
1141
1434
  _gi="$NEXUS_DIR/.gitignore"
1142
- if [ -f "$NEXUS_DIR/.rnex/scripts/wiki-lint-trigger.sh" ] || [ -f "$NEXUS_DIR/scripts/wiki-lint-trigger.sh" ]; then
1143
- if [ ! -f "$_gi" ] || ! grep -qF ".rnex/.lint_trigger_counter" "$_gi" 2>/dev/null; then
1144
- printf '\n# Repo Nexus internal state\n.rnex/.lint_trigger_counter\nwiki/.lint_trigger_counter\n.lint_trigger_counter\n' >> "$_gi"
1145
- log_dim "Added '.rnex/.lint_trigger_counter' to .gitignore"
1146
- fi
1435
+ if [ ! -f "$_gi" ] || ! grep -qF "$RNEX_LOCAL_CONFIG_FILE" "$_gi" 2>/dev/null; then
1436
+ printf '\n# Local machine-specific configuration\n%s\n.rnex.local.yaml\n' "$RNEX_LOCAL_CONFIG_FILE" >> "$_gi"
1437
+ log_dim "Added '$RNEX_LOCAL_CONFIG_FILE' to .gitignore"
1147
1438
  fi
1148
1439
 
1149
1440
  cmd_sync
@@ -1321,7 +1612,7 @@ cmd_help() {
1321
1612
  sync Reconcile scope links, plugins & member .rnex/ directories
1322
1613
 
1323
1614
  REPO MANAGEMENT
1324
- add [--no-rnex-dir] <name> <path> Register local repo (creates repos/<name> and .rnex/)
1615
+ add [--local] [--no-rnex-dir] <name> <path> Register member repo (--local writes to .local.rnex.yaml)
1325
1616
  remove <name> Unregister repo and unlink scope
1326
1617
  list List all registered member repos with scope & .rnex status
1327
1618
  status Inspect workspace health, active repos, and plugins
@@ -1340,7 +1631,8 @@ cmd_help() {
1340
1631
  EXAMPLES
1341
1632
  rnex init # Initialize workspace in current folder
1342
1633
  rnex install # Install rnex CLI globally to ~/.local/bin
1343
- rnex add my-app ~/code/my-app # Register repo (links into repos/my-app, enables .rnex/)
1634
+ rnex add my-app ~/code/my-app # Register repo in rnex.yaml (team-visible)
1635
+ rnex add my-app ~/code/my-app --local # Register local path in .local.rnex.yaml
1344
1636
  rnex add --no-rnex-dir my-app ~/code/my-app # Register repo with .rnex/ disabled
1345
1637
  rnex rnex-dir disable my-app # Disable .rnex directory for a repo
1346
1638
  rnex rnex-dir enable my-app # Re-enable .rnex directory for a repo
@@ -1349,7 +1641,7 @@ cmd_help() {
1349
1641
  rnex plugin enable karpathy-llm # Enable Karpathy LLM plugin
1350
1642
  rnex hide my-app # Temporarily hide from active indexing
1351
1643
  rnex show my-app # Bring back into active scope
1352
- rnex sync # Reconcile all links from $RNEX_CONFIG_FILE
1644
+ rnex sync # Reconcile all links from config
1353
1645
 
1354
1646
  EOF
1355
1647
  }
@@ -22,16 +22,11 @@ Reference specification: [setup-karpathy-wiki.md](https://github.com/nu-nenoi/ai
22
22
  ### 3. Complete Karpathy LLM Wiki Architecture
23
23
  * **`/raw/` Intake Directory:** Append-only directory where unmodified source material (articles, transcripts, docs, meeting notes) is deposited. Includes `.gitkeep`.
24
24
  * **`/wiki/` Curated Knowledge Base:** Interlinked atomic markdown pages, each with typed frontmatter relations (`sources`, `related`, `extends`, `contradicts`, `mentioned_in`).
25
- * **`/wiki/index.md` Control & Navigation Index:** Master categorized catalog containing `lint_trigger: enabled|disabled` to control autonomous maintenance.
25
+ * **`/wiki/index.md` Navigation Index:** Master categorized catalog organizing atomic concepts, architecture decisions, and cross-project knowledge.
26
26
  * **`/wiki/hot.md` Rolling Context Cache:** High-density ~500-word orientation summary for rapid agent onboarding without full wiki scans (especially for codebase knowledge and second-brain wikis).
27
27
  * **`/wiki/_log.md` Audit Trail:** Append-only log recording every ingest and lint operation with timestamped details.
28
- * **`/wiki/.lint_trigger_counter` Session Counter:** Machine-local state tracking session activity (ignored in `.gitignore`).
29
28
 
30
- ### 4. Autonomous Lint Trigger Script (`scripts/wiki-lint-trigger.sh`)
31
- * Lightweight POSIX script checking `lint_trigger: enabled` and incrementing `wiki/.lint_trigger_counter`.
32
- * Alerts agents with `[WIKI MAINTENANCE DUE]: Pending /raw/ files or wiki health checks detected. Run wiki-lint.` on session 1 and every 15 sessions.
33
-
34
- ### 5. Standardized Agent Workflows (`workflows/`)
29
+ ### 4. Standardized Agent Workflows (`workflows/`)
35
30
  * **`wiki-ingest.md` (8 Steps):** Decomposes raw source documents into 5–25 atomic wiki pages with frontmatter relations.
36
31
  * **`wiki-lint.md` (10 Steps):** Integrity audit protocol to validate paths, recompute `mentioned_in`, eliminate orphans, merge duplicates, audit inconsistencies, identify gaps, suggest source candidates, and rebuild indexes.
37
32
 
@@ -69,10 +64,6 @@ When an AI agent or developer sets up the Karpathy LLM Wiki in a repository or w
69
64
  - Codebase → `architecture/`, `decisions/`, `runbooks/`, `people/`
70
65
  - **Agent decides** — infer structure from the first batch of ingested content
71
66
 
72
- 4. **[Q4] Enable wiki automation now?**
73
- - **Yes** — set `lint_trigger: enabled` in `/wiki/index.md` frontmatter
74
- - **No** — set `lint_trigger: disabled` (can be changed anytime)
75
-
76
67
  ---
77
68
 
78
69
  ## Directory Layout Scaffolding
@@ -84,7 +75,7 @@ my-workspace/
84
75
  ├── raw/
85
76
  │ └── .gitkeep # Intake for unmodified source documents
86
77
  ├── wiki/
87
- │ ├── index.md # Master catalog + lint_trigger toggle
78
+ │ ├── index.md # Master catalog
88
79
  │ ├── hot.md # Rolling ~500-word quick-orient context
89
80
  │ └── _log.md # Ingestion & lint audit history
90
81
  ├── .rnex/
@@ -95,12 +86,9 @@ my-workspace/
95
86
  │ ├── workflows/
96
87
  │ │ ├── wiki-ingest.md # 8-step decomposition & ingestion workflow
97
88
  │ │ └── wiki-lint.md # 10-step graph validation & maintenance workflow
98
- │ ├── scripts/
99
- │ │ └── wiki-lint-trigger.sh # Executable session counter & lint alert
100
- │ ├── templates/
101
- │ │ ├── wiki-page.template.md # Atomic page template with typed relations
102
- │ │ └── LLM_WIKI.sample.md # Sample wiki walkthrough
103
- │ └── .lint_trigger_counter # Session counter (gitignored)
89
+ │ └── templates/
90
+ │ ├── wiki-page.template.md # Atomic page template with typed relations
91
+ │ └── LLM_WIKI.sample.md # Sample wiki walkthrough
104
92
  └── rnex.yaml # Plugin configuration
105
93
  ```
106
94
 
@@ -115,11 +103,10 @@ rnex plugin enable karpathy-llm
115
103
  ```
116
104
 
117
105
  This command:
118
- 1. Adds `karpathy-llm` to `plugins:` in `rnex.yaml` with default configuration (`lint_trigger_enabled: true`).
119
- 2. Copies initial templates (`wiki/index.md`, `wiki/_log.md`, `wiki/hot.md`, `raw/.gitkeep`, `.rnex/templates/wiki-page.template.md`, `.rnex/templates/LLM_WIKI.sample.md`, `.rnex/scripts/wiki-lint-trigger.sh`).
106
+ 1. Adds `karpathy-llm` to `plugins:` in `rnex.yaml`.
107
+ 2. Copies initial templates (`wiki/index.md`, `wiki/_log.md`, `wiki/hot.md`, `raw/.gitkeep`, `.rnex/templates/wiki-page.template.md`, `.rnex/templates/LLM_WIKI.sample.md`).
120
108
  3. Links `KARPATHY_RULES.md` and workflows into `.rnex/rules/` and `.rnex/workflows/`.
121
- 4. Ensures `.rnex/.lint_trigger_counter` is added to `.gitignore`.
122
- 5. Syncs scope links and AI context files across all registered member repositories via `rnex sync`.
109
+ 4. Syncs scope links and AI context files across all registered member repositories via `rnex sync`.
123
110
 
124
111
  ### Option 2: Declarative in `rnex.yaml`
125
112
 
@@ -127,8 +114,7 @@ Configure `karpathy-llm` under `plugins:` in `rnex.yaml`:
127
114
 
128
115
  ```yaml
129
116
  plugins:
130
- karpathy-llm:
131
- lint_trigger_enabled: true
117
+ karpathy-llm: {}
132
118
  ```
133
119
 
134
120
  Then synchronize:
@@ -139,13 +125,114 @@ rnex sync
139
125
 
140
126
  ---
141
127
 
128
+ ## Configuration Reference
129
+
130
+ The plugin supports two levels of configuration:
131
+ 1. **Repo Config (`rnex.yaml`)**: Shared across your team and version-controlled. Configures repository-level structure, file paths, and indexing rules.
132
+ 2. **Local Config (`.local.rnex.yaml`)**: Machine-specific and gitignored. Configures git hook triggers, deterministic checks, and your preferred local AI runner command.
133
+
134
+ ### 1. Shared Repo Configuration (`rnex.yaml`)
135
+
136
+ ```yaml
137
+ plugins:
138
+ karpathy-llm:
139
+ # Directory paths relative to workspace root (defaults shown)
140
+ wiki_dir: wiki # Directory for curated atomic markdown pages
141
+ raw_dir: raw # Append-only directory for unmodified intake documents
142
+
143
+ # Master catalog auto-indexing (default: true)
144
+ # Automatically rebuilds categorized links in wiki/index.md when pages change
145
+ auto_index: true
146
+ ```
147
+
148
+ ### 2. Local Machine Configuration (`.local.rnex.yaml`)
149
+
150
+ Use this file to customize how your local workstation executes wiki maintenance (e.g., via git hooks, deterministic scripts, or provider-agnostic AI CLI runners):
151
+
152
+ ```yaml
153
+ plugins:
154
+ karpathy-llm:
155
+ # Optional automated git hook trigger (default: unset / manual only):
156
+ # "git-post-commit" - Runs immediately after a successful commit (Recommended: non-blocking)
157
+ # "git-pre-push" - Runs before pushing changes to remote
158
+ # "git-post-merge" - Runs after pulling upstream updates from teammates
159
+ # Omit or leave unset for purely manual maintenance (default).
160
+ lint_trigger: git-post-commit
161
+
162
+ # Stage 1: Deterministic graph maintenance (default: true)
163
+ # Executes zero-token AST/regex checks to validate broken links, recompute mentioned_in,
164
+ # and find orphaned pages without calling an LLM (<50ms, free, offline).
165
+ run_deterministic_checks: true
166
+
167
+ # Stage 2: Provider-agnostic AI command runner (default: "")
168
+ # Executed ONLY when semantic synthesis is required (e.g. decomposing /raw/ docs via wiki-ingest).
169
+ # The trigger pipes the workflow markdown instructions to this command via standard input (stdin).
170
+ ai_cmd: "llm -m openrouter/auto"
171
+
172
+ # Examples for popular CLI tools:
173
+ # ai_cmd: "gemini run" # Google Gemini / Antigravity CLI
174
+ # ai_cmd: "claude -p" # Claude Code CLI
175
+ # ai_cmd: "ollama run llama3" # Local offline model
176
+ # ai_cmd: "aider --message" # Aider CLI
177
+ # ai_cmd: "" # Empty: Prompt-only mode (prints terminal notification)
178
+
179
+ # Terminal notifications on commit (default: true)
180
+ # Displays non-blocking alerts in your terminal right after git commit completes.
181
+ notify_on_changes: true
182
+ ```
183
+
184
+ ### Detailed Option Descriptions
185
+
186
+ #### `auto_index` (Repo Config)
187
+ * **What it does:** Automatically keeps `/wiki/index.md` (the master catalog) synchronized with all atomic pages in `/wiki/`.
188
+ * **How it works:** During `wiki-ingest` and `wiki-lint`, the tool inspects each page's frontmatter (`title`, `tags`, directory category) and updates the categorized link sections in `index.md`.
189
+ * **Why you need it:** AI coding assistants read `wiki/index.md` first as a high-level "navigation map" to locate relevant concepts without scanning hundreds of individual markdown files (saving massive amounts of context tokens). If disabled (`false`), you must manually maintain links in `index.md`.
190
+
191
+ #### `lint_trigger` (Local Config)
192
+ * **What it does:** Optional git hook trigger to automate wiki graph audits and maintenance workflows (`wiki-lint` and `wiki-ingest`).
193
+ * **Default:** Unset / omitted. Automated triggers are **disabled by default**; wiki maintenance is purely manual unless you explicitly opt into a Git hook here.
194
+ * **Supported opt-in values:**
195
+ * `git-post-commit` *(Recommended)*: Fires immediately after a `git commit` succeeds. It is completely non-blocking and checks `git diff-tree` to see if files in `/raw/` or `/wiki/` were added or modified.
196
+ * `git-pre-push`: Fires before pushing changes upstream, catching dead links or unparsed notes before publishing to the team.
197
+ * `git-post-merge`: Fires after `git pull` when teammates have added new wiki notes or intake documents.
198
+ * **Why you need it:** Lets you optionally bind wiki maintenance to a specific Git lifecycle event without nagging prompts or timer counters. If you prefer running workflows manually on demand, leave this field omitted.
199
+
200
+ #### `notify_on_changes` (Local Config)
201
+ * **What it does:** Controls whether helpful status messages and action reminders are printed to your terminal stdout.
202
+ * **When is it triggered?** Triggered **immediately after a git operation completes** (e.g., right after `git commit` finishes writing the commit object, or during `git push`).
203
+ * If new documents were committed into `/raw/`: prints an alert (e.g. `[WIKI] 2 new intake documents in /raw/. Run wiki-ingest with your AI assistant.`).
204
+ * If broken links or orphans were detected: prints a summary notice highlighting the pages that need attention.
205
+ * **Why you need it:** Provides immediate visibility into pending wiki operations without blocking or slowing down your Git workflow. Set to `false` for silent background execution.
206
+
207
+ #### `run_deterministic_checks` (Local Config)
208
+ * **What it does:** Enables fast, offline graph analysis before invoking any LLM.
209
+ * **How it works:** Runs a local script that parses Markdown link targets and frontmatter relations (`sources`, `related`, `extends`, `contradicts`). It validates that target files exist, recomputes reciprocal `mentioned_in: []` backlinks, and identifies orphan pages.
210
+ * **Why you need it:** Resolves 90% of routine wiki maintenance in <50ms without spending API tokens, hitting rate limits, or risking LLM path hallucinations.
211
+
212
+ #### `ai_cmd` (Local Config)
213
+ * **What it does:** A provider-agnostic shell command template used to execute semantic LLM tasks (such as decomposing an intake document via `wiki-ingest` or resolving factual contradictions).
214
+ * **How it works:** When semantic work is needed, the trigger pipes the task prompt and workflow file into this shell command via standard input (`stdin`).
215
+ * **Why you need it:** Decouples your wiki workflow from any single vendor. Works with Simon Willison's `llm`, Google Gemini / Antigravity CLI, Anthropic Claude Code, Ollama, Aider, or custom shell scripts. If left blank (`""`), the system operates in prompt-only mode, reminding you to run the workflow in your interactive chat assistant.
216
+
217
+ ### Summary Reference Table
218
+
219
+ | Field | Scope / File | Type | Default | Values / Behavior |
220
+ |:---|:---|:---|:---|:---|
221
+ | `auto_index` | Repo (`rnex.yaml`) | `boolean` | `true` | Auto-rebuilds categorized links in `wiki/index.md`. Set to `false` for manual curation. |
222
+ | `wiki_dir` | Repo (`rnex.yaml`) | `string` | `wiki` | Directory containing atomic domain pages. |
223
+ | `raw_dir` | Repo (`rnex.yaml`) | `string` | `raw` | Append-only directory for unmodified source materials. |
224
+ | `lint_trigger` | Local (`.local.rnex.yaml`) | `string` | *(unset)* | Optional opt-in Git hook: `git-post-commit`, `git-pre-push`, `git-post-merge`. Unset = purely manual. |
225
+ | `run_deterministic_checks` | Local (`.local.rnex.yaml`) | `boolean` | `true` | Offline zero-token validation of broken links, `mentioned_in`, and orphans. |
226
+ | `ai_cmd` | Local (`.local.rnex.yaml`) | `string` | `""` | Command template for semantic tasks. If unset, operates in prompt-only mode. |
227
+ | `notify_on_changes` | Local (`.local.rnex.yaml`) | `boolean` | `true` | Terminal alerts printed right after git commit/push when `/raw/` or wiki needs attention. |
228
+
229
+ ---
230
+
142
231
  ## Everyday Operation & Cadence
143
232
 
144
233
  1. **Intake:** Drop raw research papers, meeting notes, PRDs, or architecture specs into `/raw/` unmodified.
145
234
  2. **Ingest:** Instruct your AI assistant: *"Run wiki-ingest on raw/source-document.md"*.
146
- 3. **Session Cadence:** After sessions where repository files were edited, run `.rnex/scripts/wiki-lint-trigger.sh`.
147
- 4. **Maintenance:** If prompted by `[WIKI MAINTENANCE DUE]`, instruct the assistant: *"Run wiki-lint"*.
148
- 5. **Toggle Automation:** Edit `lint_trigger: enabled` or `lint_trigger: disabled` in `/wiki/index.md` anytime.
235
+ 3. **Maintenance:** Run the `wiki-lint` workflow to validate relations, prune orphans, and update `mentioned_in` links.
149
236
 
150
237
  ---
151
238
 
@@ -56,9 +56,7 @@ When working in a repository with an active Karpathy LLM Wiki (`/wiki/` and `/ra
56
56
  - **Intake**: All source material (articles, transcripts, docs, notes) goes to `/raw/` unmodified. Never write directly to `/wiki/` without ingesting.
57
57
  - **Orientation**: Before answering domain questions, read `/wiki/index.md` to find relevant pages, then read only those pages. If `hot.md` exists, read it first as a quick-orient step.
58
58
  - **Ingestion**: When files appear in `/raw/`, run the `wiki-ingest` workflow (`.rnex/workflows/wiki-ingest.md`). One source document typically produces many atomic pages (commonly 5–25 pages) — do not collapse a source into a single file.
59
- - **Cadence**: After any session where repository files were created, edited, or deleted, run `.rnex/scripts/wiki-lint-trigger.sh`. If it outputs `[WIKI MAINTENANCE DUE]`, run the `wiki-lint` workflow (`.rnex/workflows/wiki-lint.md`) before stopping.
60
- - **No-op sessions**: Do not run the trigger after read-only or purely conversational sessions where no files changed.
61
- - **Enable/disable**: Wiki automation is controlled by `lint_trigger_enabled: true|false` in `rnex.yaml` (and `lint_trigger: enabled|disabled` in `/wiki/index.md` frontmatter). Edit either field to toggle.
59
+ - **Maintenance**: Run the `wiki-lint` workflow (`.rnex/workflows/wiki-lint.md`) to validate paths, update `mentioned_in`, and preserve graph integrity.
62
60
 
63
61
  ---
64
62
 
@@ -16,4 +16,3 @@ templates:
16
16
  - templates/raw.gitkeep: raw/.gitkeep
17
17
  - templates/wiki-page.sample.md: .rnex/templates/wiki-page.template.md
18
18
  - templates/LLM_WIKI.sample.md: .rnex/templates/LLM_WIKI.sample.md
19
- - scripts/wiki-lint-trigger.sh: .rnex/scripts/wiki-lint-trigger.sh
@@ -56,9 +56,7 @@ When working in a repository with an active Karpathy LLM Wiki (`/wiki/` and `/ra
56
56
  - **Intake**: All source material (articles, transcripts, docs, notes) goes to `/raw/` unmodified. Never write directly to `/wiki/` without ingesting.
57
57
  - **Orientation**: Before answering domain questions, read `/wiki/index.md` to find relevant pages, then read only those pages. If `hot.md` exists, read it first as a quick-orient step.
58
58
  - **Ingestion**: When files appear in `/raw/`, run the `wiki-ingest` workflow (`.rnex/workflows/wiki-ingest.md`). One source document typically produces many atomic pages (commonly 5–25 pages) — do not collapse a source into a single file.
59
- - **Cadence**: After any session where repository files were created, edited, or deleted, run `.rnex/scripts/wiki-lint-trigger.sh`. If it outputs `[WIKI MAINTENANCE DUE]`, run the `wiki-lint` workflow (`.rnex/workflows/wiki-lint.md`) before stopping.
60
- - **No-op sessions**: Do not run the trigger after read-only or purely conversational sessions where no files changed.
61
- - **Enable/disable**: Wiki automation is controlled by `lint_trigger_enabled: true|false` in `rnex.yaml` (and `lint_trigger: enabled|disabled` in `/wiki/index.md` frontmatter). Edit either field to toggle.
59
+ - **Maintenance**: Run the `wiki-lint` workflow (`.rnex/workflows/wiki-lint.md`) to validate paths, update `mentioned_in`, and preserve graph integrity.
62
60
 
63
61
  ---
64
62
 
@@ -6,4 +6,4 @@ Append-only audit trail recording all ingest (`wiki-ingest`) and maintenance (`w
6
6
 
7
7
  ### Initial Setup — YYYY-MM-DD
8
8
  * **Action:** Initialized Karpathy LLM Wiki architecture via `karpathy-llm` plugin.
9
- * **Control State:** `lint_trigger: enabled`. Intake directory `/raw/` created.
9
+ * **Intake:** Intake directory `/raw/` created.
@@ -8,4 +8,4 @@
8
8
  * **Key Directives:**
9
9
  1. Maintain atomic pages with typed frontmatter relations.
10
10
  2. Update `/wiki/index.md` and this hot cache upon new ingests.
11
- 3. Run `scripts/wiki-lint-trigger.sh` after sessions modifying project files.
11
+ 3. Run `wiki-lint` workflow to audit and maintain graph integrity.
@@ -1,7 +1,6 @@
1
1
  ---
2
2
  title: Wiki Index
3
3
  last_updated: YYYY-MM-DD
4
- lint_trigger: enabled # set to "disabled" to pause all wiki automation
5
4
  ---
6
5
 
7
6
  # Wiki Index
@@ -40,10 +40,6 @@ Ask ALL of the following questions and wait for answers:
40
40
  - Structured — subfolders by category, chosen based on Q2 answer
41
41
  - Agent decides — infer structure from the first batch of ingested content
42
42
 
43
- [Q4] Enable wiki automation now?
44
- - Yes — set `lint_trigger: enabled` in `/wiki/index.md` frontmatter
45
- - No — set `lint_trigger: disabled` (can be changed at any time by editing that field)
46
-
47
43
  ---
48
44
 
49
45
  ### 1. Directories and Files
@@ -58,27 +54,23 @@ Ask ALL of the following questions and wait for answers:
58
54
  - Content archive → `sources/`, `people/`, `tools/`, `concepts/`
59
55
  - Codebase → `architecture/`, `decisions/`, `runbooks/`, `people/`
60
56
 
61
- **`/wiki/index.md`** — Master navigation index and wiki control file. Contains:
62
- - YAML frontmatter with `lint_trigger: enabled|disabled` — controls whether the autonomous trigger runs. Committed to version control; toggling is a team-visible decision.
57
+ **`/wiki/index.md`** — Master navigation index. Contains:
63
58
  - Categorized links to every wiki page. Auto-maintained after every ingest and lint run.
64
59
 
65
60
  **`/wiki/_log.md`** — Append-only operation log. Every ingest and lint run appends a timestamped entry.
66
61
 
67
62
  **`/wiki/hot.md`** *(create only for second brain or codebase wiki)* — Rolling ~500-word cache of the most recently relevant context. Lets an agent orient without reading the full wiki.
68
63
 
69
- **`/wiki/.lint_trigger_counter`** — Session counter used by the lint trigger script. Machine-local state. Add to `.gitignore`.
70
-
71
64
  ---
72
65
 
73
66
  ### 2. Index File Format
74
67
 
75
- `/wiki/index.md` uses its own frontmatter schema (it is the wiki control file, not a regular page):
68
+ `/wiki/index.md` uses its own frontmatter schema (it is the wiki navigation file, not an atomic content page):
76
69
 
77
70
  ```yaml
78
71
  ---
79
72
  title: Wiki Index
80
73
  last_updated: YYYY-MM-DD
81
- lint_trigger: enabled # set to "disabled" to pause all wiki automation
82
74
  ---
83
75
  ```
84
76
 
@@ -122,9 +114,7 @@ In the file chosen in Q1, append:
122
114
  - **Intake**: All source material (articles, transcripts, docs, notes) goes to `/raw/` unmodified. Never write directly to `/wiki/` without ingesting.
123
115
  - **Orientation**: Before answering domain questions, read `/wiki/index.md` to find relevant pages, then read only those pages. If `hot.md` exists, read it first as a quick-orient step.
124
116
  - **Ingestion**: When files appear in `/raw/`, run the `wiki-ingest` workflow. One source document typically produces many atomic pages — do not collapse a source into a single file.
125
- - **Cadence**: After any session where repository files were created, edited, or deleted, run `scripts/wiki-lint-trigger.sh`. If it outputs `[WIKI MAINTENANCE DUE]`, run the `wiki-lint` workflow before stopping.
126
- - **No-op sessions**: Do not run the trigger after read-only or purely conversational sessions where no files changed.
127
- - **Enable/disable**: Wiki automation is controlled by `lint_trigger: enabled|disabled` in `/wiki/index.md` frontmatter. Edit that field to toggle — the change is committed and visible to the whole team.
117
+ - **Maintenance**: Run the `wiki-lint` workflow to validate paths, update `mentioned_in`, and preserve graph integrity.
128
118
  ```
129
119
 
130
120
  ---
@@ -157,23 +147,5 @@ Create workflow instruction files at `.agent/workflows/` (or `.agent/skills/` de
157
147
 
158
148
  ---
159
149
 
160
- ### 6. Autonomous Lint Trigger
161
-
162
- Create `scripts/wiki-lint-trigger.sh` (POSIX shell):
163
- - Check if `wiki/index.md` exists and contains `lint_trigger: enabled`. If not, exit silently with code `0`.
164
- ```sh
165
- grep -q "lint_trigger: enabled" wiki/index.md 2>/dev/null || exit 0
166
- ```
167
- - Read and increment a counter stored in `wiki/.lint_trigger_counter`.
168
- - If counter is `1` or a multiple of `15`, print:
169
- `[WIKI MAINTENANCE DUE]: Pending /raw/ files or wiki health checks detected. Run wiki-lint.`
170
- - Otherwise exit silently with code `0`.
171
- - Make executable: `chmod +x scripts/wiki-lint-trigger.sh`.
172
-
173
- To disable: set `lint_trigger: disabled` in `/wiki/index.md` frontmatter.
174
- To re-enable: set `lint_trigger: enabled`.
175
-
176
- ---
177
-
178
150
  All files must be self-contained with no external dependencies.
179
151
  ```
@@ -1,44 +0,0 @@
1
- #!/bin/sh
2
- # ============================================================================
3
- # .rnex/scripts/wiki-lint-trigger.sh — Autonomous Karpathy Wiki Lint Trigger
4
- # ============================================================================
5
-
6
- # 1. Check rnex.yaml configuration if present
7
- if [ -f "rnex.yaml" ]; then
8
- _disabled=$(awk '
9
- /^plugins:/ { in_p=1; next }
10
- in_p && /^[^ #]/ { exit }
11
- in_p && /^ karpathy-llm:[ ]*$/ { in_k=1; next }
12
- in_k && /^ lint_trigger_enabled:[ ]*false/ { print "yes"; exit }
13
- in_k && !/^ / && !/^[ ]*#/ { in_k=0 }
14
- ' rnex.yaml)
15
- if [ "$_disabled" = "yes" ]; then
16
- exit 0
17
- fi
18
- fi
19
-
20
- # 2. Check if wiki/index.md exists and contains lint_trigger: enabled
21
- grep -q "lint_trigger: enabled" wiki/index.md 2>/dev/null || exit 0
22
-
23
- COUNTER_DIR=".rnex"
24
- [ -d "$COUNTER_DIR" ] || COUNTER_DIR="wiki"
25
- COUNTER_FILE="$COUNTER_DIR/.lint_trigger_counter"
26
-
27
- # Read and increment session counter
28
- count=0
29
- if [ -f "$COUNTER_FILE" ]; then
30
- count=$(cat "$COUNTER_FILE" 2>/dev/null || echo 0)
31
- fi
32
- case "$count" in
33
- ''|*[!0-9]*) count=0 ;;
34
- esac
35
-
36
- count=$((count + 1))
37
- printf '%s\n' "$count" > "$COUNTER_FILE" 2>/dev/null || true
38
-
39
- # If counter is 1 or a multiple of 15, print maintenance due notice
40
- if [ "$count" -eq 1 ] || [ $((count % 15)) -eq 0 ]; then
41
- printf '[WIKI MAINTENANCE DUE]: Pending /raw/ files or wiki health checks detected. Run wiki-lint.\n'
42
- fi
43
-
44
- exit 0