nexus-dev-toolkit 3.1.3__tar.gz → 3.1.4__tar.gz

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.
Files changed (41) hide show
  1. {nexus_dev_toolkit-3.1.3/nexus_dev_toolkit.egg-info → nexus_dev_toolkit-3.1.4}/PKG-INFO +22 -10
  2. {nexus_dev_toolkit-3.1.3 → nexus_dev_toolkit-3.1.4}/README.md +21 -9
  3. {nexus_dev_toolkit-3.1.3 → nexus_dev_toolkit-3.1.4}/nexus_cli.py +176 -43
  4. {nexus_dev_toolkit-3.1.3 → nexus_dev_toolkit-3.1.4/nexus_dev_toolkit.egg-info}/PKG-INFO +22 -10
  5. {nexus_dev_toolkit-3.1.3 → nexus_dev_toolkit-3.1.4}/nexus_dev_toolkit.egg-info/SOURCES.txt +1 -0
  6. {nexus_dev_toolkit-3.1.3 → nexus_dev_toolkit-3.1.4}/pyproject.toml +1 -1
  7. nexus_dev_toolkit-3.1.4/tests/test_cli.py +489 -0
  8. nexus_dev_toolkit-3.1.4/tools/epav/graph_backend.py +88 -0
  9. {nexus_dev_toolkit-3.1.3 → nexus_dev_toolkit-3.1.4}/tools/epav/skills/apply.md +5 -2
  10. {nexus_dev_toolkit-3.1.3 → nexus_dev_toolkit-3.1.4}/tools/epav/skills/epav.md +1 -1
  11. {nexus_dev_toolkit-3.1.3 → nexus_dev_toolkit-3.1.4}/tools/epav/skills/evaluate.md +9 -6
  12. {nexus_dev_toolkit-3.1.3 → nexus_dev_toolkit-3.1.4}/tools/epav/skills/plan.md +4 -4
  13. {nexus_dev_toolkit-3.1.3 → nexus_dev_toolkit-3.1.4}/tools/epav/skills/validate.md +5 -5
  14. {nexus_dev_toolkit-3.1.3 → nexus_dev_toolkit-3.1.4}/tools/epav/task_loader.py +7 -20
  15. nexus_dev_toolkit-3.1.3/tests/test_cli.py +0 -225
  16. {nexus_dev_toolkit-3.1.3 → nexus_dev_toolkit-3.1.4}/LICENSE +0 -0
  17. {nexus_dev_toolkit-3.1.3 → nexus_dev_toolkit-3.1.4}/nexus_dev_toolkit.egg-info/dependency_links.txt +0 -0
  18. {nexus_dev_toolkit-3.1.3 → nexus_dev_toolkit-3.1.4}/nexus_dev_toolkit.egg-info/entry_points.txt +0 -0
  19. {nexus_dev_toolkit-3.1.3 → nexus_dev_toolkit-3.1.4}/nexus_dev_toolkit.egg-info/requires.txt +0 -0
  20. {nexus_dev_toolkit-3.1.3 → nexus_dev_toolkit-3.1.4}/nexus_dev_toolkit.egg-info/top_level.txt +0 -0
  21. {nexus_dev_toolkit-3.1.3 → nexus_dev_toolkit-3.1.4}/nexus_server.py +0 -0
  22. {nexus_dev_toolkit-3.1.3 → nexus_dev_toolkit-3.1.4}/setup.cfg +0 -0
  23. {nexus_dev_toolkit-3.1.3 → nexus_dev_toolkit-3.1.4}/tests/test_server.py +0 -0
  24. {nexus_dev_toolkit-3.1.3 → nexus_dev_toolkit-3.1.4}/tools/__init__.py +0 -0
  25. {nexus_dev_toolkit-3.1.3 → nexus_dev_toolkit-3.1.4}/tools/agents/__init__.py +0 -0
  26. {nexus_dev_toolkit-3.1.3 → nexus_dev_toolkit-3.1.4}/tools/agents/code-reviewer.md +0 -0
  27. {nexus_dev_toolkit-3.1.3 → nexus_dev_toolkit-3.1.4}/tools/agents/database-reviewer.md +0 -0
  28. {nexus_dev_toolkit-3.1.3 → nexus_dev_toolkit-3.1.4}/tools/agents/deployment-reviewer.md +0 -0
  29. {nexus_dev_toolkit-3.1.3 → nexus_dev_toolkit-3.1.4}/tools/agents/monitoring-reviewer.md +0 -0
  30. {nexus_dev_toolkit-3.1.3 → nexus_dev_toolkit-3.1.4}/tools/agents/performance-reviewer.md +0 -0
  31. {nexus_dev_toolkit-3.1.3 → nexus_dev_toolkit-3.1.4}/tools/epav/__init__.py +0 -0
  32. {nexus_dev_toolkit-3.1.3 → nexus_dev_toolkit-3.1.4}/tools/epav/arch_ingest.py +0 -0
  33. {nexus_dev_toolkit-3.1.3 → nexus_dev_toolkit-3.1.4}/tools/epav/package_resolver.py +0 -0
  34. {nexus_dev_toolkit-3.1.3 → nexus_dev_toolkit-3.1.4}/tools/epav/project_rules.py +0 -0
  35. {nexus_dev_toolkit-3.1.3 → nexus_dev_toolkit-3.1.4}/tools/epav/skills/__init__.py +0 -0
  36. {nexus_dev_toolkit-3.1.3 → nexus_dev_toolkit-3.1.4}/tools/epav/skills/code-review.md +0 -0
  37. {nexus_dev_toolkit-3.1.3 → nexus_dev_toolkit-3.1.4}/tools/epav/skills/database-review.md +0 -0
  38. {nexus_dev_toolkit-3.1.3 → nexus_dev_toolkit-3.1.4}/tools/epav/skills/deployment-review.md +0 -0
  39. {nexus_dev_toolkit-3.1.3 → nexus_dev_toolkit-3.1.4}/tools/epav/skills/monitoring-review.md +0 -0
  40. {nexus_dev_toolkit-3.1.3 → nexus_dev_toolkit-3.1.4}/tools/epav/skills/performance-review.md +0 -0
  41. {nexus_dev_toolkit-3.1.3 → nexus_dev_toolkit-3.1.4}/tools/epav/skills/scaffold.md +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: nexus-dev-toolkit
3
- Version: 3.1.3
3
+ Version: 3.1.4
4
4
  Summary: Developer workflow toolkit for Claude Code — Day 0 scaffold + Day 1 EPAV
5
5
  Author-email: Ronald dela Cruz <rcdelacruz@users.noreply.github.com>
6
6
  License-Expression: MIT
@@ -22,7 +22,7 @@ Dynamic: license-file
22
22
  # nexus-dev-toolkit
23
23
 
24
24
 
25
- Developer workflow toolkit for Claude Code. Gives any team a structured Day 0 scaffold and repeatable Day 1 feature cycle via the EPAV methodology.
25
+ Developer workflow toolkit for Claude Code and OpenCode. Gives any team a structured Day 0 scaffold and repeatable Day 1 feature cycle via the EPAV methodology.
26
26
 
27
27
  **[Documentation](https://nexus.coderstudio.co/docs)**
28
28
 
@@ -70,6 +70,13 @@ uv tool install graphifyy # PyPI package name has double y; command is "graphi
70
70
  graphify install # registers /graphify skill into Claude Code
71
71
  ```
72
72
 
73
+ **codegraph** _(alternative to graphify)_ — a different knowledge-graph tool EPAV skills can use instead. Pick one, not both; `nexus doctor` warns if it finds graphs from both built in the same project.
74
+
75
+ ```bash
76
+ npm i -g @colbymchenry/codegraph
77
+ codegraph install # wires codegraph into Claude Code / OpenCode / etc.
78
+ ```
79
+
73
80
  ### 2. Install nexus-dev-toolkit
74
81
 
75
82
  ```bash
@@ -80,8 +87,9 @@ uv tool install nexus-dev-toolkit
80
87
 
81
88
  ```bash
82
89
  cd my-project
83
- nexus init . # Claude Code (default)
84
- nexus init . --tool opencode # OpenCode
90
+ nexus init . # Claude Code (default), prompts for graphify/codegraph/none
91
+ nexus init . --tool opencode # OpenCode
92
+ nexus init . --graph-backend codegraph # skip the prompt, use codegraph
85
93
  ```
86
94
 
87
95
  ### 4. Place your reference docs
@@ -111,12 +119,13 @@ Open the project in Claude Code and run:
111
119
 
112
120
  ### 6. Build the knowledge graph
113
121
 
114
- After `/scaffold` completes, run in Claude Code:
122
+ After `/scaffold` completes, build whichever backend you chose at init:
115
123
  ```
116
- /graphify .
124
+ /graphify . # if you chose graphify
125
+ codegraph install && codegraph init # if you chose codegraph, run in your terminal
117
126
  ```
118
127
 
119
- This generates `graphify-out/graph.json` — required by all EPAV skills before starting Day 1.
128
+ This generates `graphify-out/graph.json` or `.codegraph/codegraph.db` — EPAV skills use whichever is present, or fall back to full file reads if neither is built yet. Run `nexus doctor` any time to check which backend is active.
120
129
 
121
130
  ---
122
131
 
@@ -138,12 +147,14 @@ Each step is a built-in skill in `.claude/commands/`. Every task starts from the
138
147
 
139
148
  ## What `nexus init` Creates
140
149
 
150
+ `settings.json`/`graphify.js` below are only created if you pick graphify (the default) at the `--graph-backend` prompt. Pick codegraph instead and neither is scaffolded — codegraph wires and syncs itself via `codegraph install && codegraph init`.
151
+
141
152
  **Claude Code** (`nexus init .`):
142
153
  ```
143
154
  .claude/
144
155
  ├── commands/ ← EPAV skills + 5 reviewer skills (/code-review, etc.)
145
156
  ├── agents/ ← 5 reviewer subagents (code-reviewer, database-reviewer, etc.)
146
- └── settings.json ← PostToolUse: graphify auto-updates after every file edit
157
+ └── settings.json ← PostToolUse: graphify auto-updates after every file edit (graphify backend only)
147
158
  knowledge/
148
159
  ├── rules/ ← coding standards, arch decisions
149
160
  ├── patterns/ ← reusable implementation patterns
@@ -158,7 +169,7 @@ knowledge/
158
169
  ├── commands/ ← same EPAV skills + reviewer skills
159
170
  ├── agents/ ← same reviewer subagents (adapted for OpenCode)
160
171
  └── plugins/
161
- └── graphify.js ← tool.execute.after: graphify auto-update
172
+ └── graphify.js ← tool.execute.after: graphify auto-update (graphify backend only)
162
173
  knowledge/ ← same structure
163
174
  opencode.json ← MCP server config
164
175
  ```
@@ -171,7 +182,8 @@ opencode.json ← MCP server config
171
182
  nexus init . # Claude Code — set up .claude/ + knowledge/ + .mcp.json
172
183
  nexus init . --tool opencode # OpenCode — set up .opencode/ + knowledge/ + opencode.json
173
184
  nexus --version # show installed version
174
- nexus update # update to latest version
185
+ nexus update # update the CLI itself; asks whether to also sync in a real terminal
186
+ nexus update --sync # skip the prompt, always sync the current project's skills/agents too
175
187
  nexus sync # sync built-in skills & agents to latest (custom files untouched)
176
188
  nexus doctor # validate project setup
177
189
 
@@ -1,7 +1,7 @@
1
1
  # nexus-dev-toolkit
2
2
 
3
3
 
4
- Developer workflow toolkit for Claude Code. Gives any team a structured Day 0 scaffold and repeatable Day 1 feature cycle via the EPAV methodology.
4
+ Developer workflow toolkit for Claude Code and OpenCode. Gives any team a structured Day 0 scaffold and repeatable Day 1 feature cycle via the EPAV methodology.
5
5
 
6
6
  **[Documentation](https://nexus.coderstudio.co/docs)**
7
7
 
@@ -49,6 +49,13 @@ uv tool install graphifyy # PyPI package name has double y; command is "graphi
49
49
  graphify install # registers /graphify skill into Claude Code
50
50
  ```
51
51
 
52
+ **codegraph** _(alternative to graphify)_ — a different knowledge-graph tool EPAV skills can use instead. Pick one, not both; `nexus doctor` warns if it finds graphs from both built in the same project.
53
+
54
+ ```bash
55
+ npm i -g @colbymchenry/codegraph
56
+ codegraph install # wires codegraph into Claude Code / OpenCode / etc.
57
+ ```
58
+
52
59
  ### 2. Install nexus-dev-toolkit
53
60
 
54
61
  ```bash
@@ -59,8 +66,9 @@ uv tool install nexus-dev-toolkit
59
66
 
60
67
  ```bash
61
68
  cd my-project
62
- nexus init . # Claude Code (default)
63
- nexus init . --tool opencode # OpenCode
69
+ nexus init . # Claude Code (default), prompts for graphify/codegraph/none
70
+ nexus init . --tool opencode # OpenCode
71
+ nexus init . --graph-backend codegraph # skip the prompt, use codegraph
64
72
  ```
65
73
 
66
74
  ### 4. Place your reference docs
@@ -90,12 +98,13 @@ Open the project in Claude Code and run:
90
98
 
91
99
  ### 6. Build the knowledge graph
92
100
 
93
- After `/scaffold` completes, run in Claude Code:
101
+ After `/scaffold` completes, build whichever backend you chose at init:
94
102
  ```
95
- /graphify .
103
+ /graphify . # if you chose graphify
104
+ codegraph install && codegraph init # if you chose codegraph, run in your terminal
96
105
  ```
97
106
 
98
- This generates `graphify-out/graph.json` — required by all EPAV skills before starting Day 1.
107
+ This generates `graphify-out/graph.json` or `.codegraph/codegraph.db` — EPAV skills use whichever is present, or fall back to full file reads if neither is built yet. Run `nexus doctor` any time to check which backend is active.
99
108
 
100
109
  ---
101
110
 
@@ -117,12 +126,14 @@ Each step is a built-in skill in `.claude/commands/`. Every task starts from the
117
126
 
118
127
  ## What `nexus init` Creates
119
128
 
129
+ `settings.json`/`graphify.js` below are only created if you pick graphify (the default) at the `--graph-backend` prompt. Pick codegraph instead and neither is scaffolded — codegraph wires and syncs itself via `codegraph install && codegraph init`.
130
+
120
131
  **Claude Code** (`nexus init .`):
121
132
  ```
122
133
  .claude/
123
134
  ├── commands/ ← EPAV skills + 5 reviewer skills (/code-review, etc.)
124
135
  ├── agents/ ← 5 reviewer subagents (code-reviewer, database-reviewer, etc.)
125
- └── settings.json ← PostToolUse: graphify auto-updates after every file edit
136
+ └── settings.json ← PostToolUse: graphify auto-updates after every file edit (graphify backend only)
126
137
  knowledge/
127
138
  ├── rules/ ← coding standards, arch decisions
128
139
  ├── patterns/ ← reusable implementation patterns
@@ -137,7 +148,7 @@ knowledge/
137
148
  ├── commands/ ← same EPAV skills + reviewer skills
138
149
  ├── agents/ ← same reviewer subagents (adapted for OpenCode)
139
150
  └── plugins/
140
- └── graphify.js ← tool.execute.after: graphify auto-update
151
+ └── graphify.js ← tool.execute.after: graphify auto-update (graphify backend only)
141
152
  knowledge/ ← same structure
142
153
  opencode.json ← MCP server config
143
154
  ```
@@ -150,7 +161,8 @@ opencode.json ← MCP server config
150
161
  nexus init . # Claude Code — set up .claude/ + knowledge/ + .mcp.json
151
162
  nexus init . --tool opencode # OpenCode — set up .opencode/ + knowledge/ + opencode.json
152
163
  nexus --version # show installed version
153
- nexus update # update to latest version
164
+ nexus update # update the CLI itself; asks whether to also sync in a real terminal
165
+ nexus update --sync # skip the prompt, always sync the current project's skills/agents too
154
166
  nexus sync # sync built-in skills & agents to latest (custom files untouched)
155
167
  nexus doctor # validate project setup
156
168
 
@@ -2,13 +2,17 @@ import json
2
2
  import shutil
3
3
  import subprocess
4
4
  import sys
5
+ import urllib.request
5
6
  from pathlib import Path
6
7
 
7
8
  import typer
8
9
  from rich.console import Console
10
+ from rich.markup import escape
9
11
  from rich.table import Table
10
12
 
11
- app = typer.Typer(name="nexus", no_args_is_help=False, help="nexus-dev-toolkit — Day 0 scaffold + Day 1 EPAV workflow for Claude Code")
13
+ from tools.epav import graph_backend
14
+
15
+ app = typer.Typer(name="nexus", no_args_is_help=False, help="nexus-dev-toolkit — Day 0 scaffold + Day 1 EPAV workflow for Claude Code and OpenCode")
12
16
  skill_app = typer.Typer(name="skill", no_args_is_help=True, help="Manage skills in .claude/commands/")
13
17
  rule_app = typer.Typer(name="rule", no_args_is_help=True, help="Manage rules in knowledge/rules/")
14
18
  agent_app = typer.Typer(name="agent", no_args_is_help=True, help="Manage subagents in .claude/agents/")
@@ -18,7 +22,31 @@ app.add_typer(agent_app, name="agent")
18
22
 
19
23
  console = Console()
20
24
 
21
- _VERSION = "3.1.3"
25
+ _VERSION = "3.1.4"
26
+
27
+
28
+ def _fetch_latest_pypi_version() -> str | None:
29
+ """Fetch the latest published version from PyPI. None on any failure — offline, timeout,
30
+ bad response — never raises."""
31
+ try:
32
+ with urllib.request.urlopen(
33
+ "https://pypi.org/pypi/nexus-dev-toolkit/json", timeout=3
34
+ ) as resp:
35
+ return json.loads(resp.read())["info"]["version"]
36
+ except Exception:
37
+ return None
38
+
39
+
40
+ def _version_tuple(v: str) -> tuple[int, ...]:
41
+ return tuple(int(part) for part in v.split("."))
42
+
43
+
44
+ def _is_outdated(installed: str, latest: str) -> bool:
45
+ try:
46
+ return _version_tuple(latest) > _version_tuple(installed)
47
+ except Exception:
48
+ return False # malformed version string from PyPI — don't false-alarm
49
+
22
50
 
23
51
  _LOGO = """\
24
52
  [cyan]███╗ ██╗███████╗██╗ ██╗██╗ ██╗███████╗[/cyan]
@@ -141,12 +169,12 @@ export const GraphifyPlugin = async ({ directory }) => {
141
169
  """
142
170
 
143
171
 
144
- def _init_project(project_dir: Path) -> list[str]:
172
+ def _init_project(project_dir: Path, backend: str = "graphify") -> list[str]:
145
173
  """
146
174
  nexus init — sets up:
147
175
  .claude/commands/ ← built-in skills
148
176
  .claude/agents/ ← built-in subagents
149
- .claude/settings.json ← PostToolUse graphify hook
177
+ .claude/settings.json ← PostToolUse graphify hook (only when backend == "graphify")
150
178
  knowledge/ ← empty scaffold
151
179
  """
152
180
  created = []
@@ -173,11 +201,12 @@ def _init_project(project_dir: Path) -> list[str]:
173
201
  shutil.copy2(src, dest)
174
202
  created.append(f".claude/agents/{agent_name}")
175
203
 
176
- # .claude/settings.json — PostToolUse graphify hook
177
- settings_path = project_dir / ".claude" / "settings.json"
178
- if not settings_path.exists():
179
- settings_path.write_text(json.dumps(_CLAUDE_SETTINGS, indent=2))
180
- created.append(".claude/settings.json")
204
+ # .claude/settings.json — PostToolUse graphify hook (codegraph syncs itself, no hook needed)
205
+ if backend == "graphify":
206
+ settings_path = project_dir / ".claude" / "settings.json"
207
+ if not settings_path.exists():
208
+ settings_path.write_text(json.dumps(_CLAUDE_SETTINGS, indent=2))
209
+ created.append(".claude/settings.json")
181
210
 
182
211
  # knowledge/ scaffold
183
212
  for d in _KNOWLEDGE_DIRS:
@@ -201,12 +230,12 @@ def _strip_claude_frontmatter(content: str) -> str:
201
230
  return "---" + "\n".join(lines) + "---" + parts[2]
202
231
 
203
232
 
204
- def _init_opencode(project_dir: Path) -> list[str]:
233
+ def _init_opencode(project_dir: Path, backend: str = "graphify") -> list[str]:
205
234
  """
206
235
  nexus init --tool opencode — sets up:
207
236
  .opencode/commands/ ← built-in skills
208
237
  .opencode/agents/ ← built-in subagents
209
- .opencode/plugins/ ← graphify PostToolUse hook
238
+ .opencode/plugins/ ← graphify PostToolUse hook (only when backend == "graphify")
210
239
  opencode.json ← MCP server config
211
240
  knowledge/ ← empty scaffold
212
241
  """
@@ -232,13 +261,14 @@ def _init_opencode(project_dir: Path) -> list[str]:
232
261
  dest.write_text(_strip_claude_frontmatter(src.read_text()), encoding="utf-8")
233
262
  created.append(f".opencode/agents/{agent_name}")
234
263
 
235
- # .opencode/plugins/graphify.js — PostToolUse hook
236
- plugins_dir = project_dir / ".opencode" / "plugins"
237
- plugins_dir.mkdir(parents=True, exist_ok=True)
238
- plugin_path = plugins_dir / "graphify.js"
239
- if not plugin_path.exists():
240
- plugin_path.write_text(_OPENCODE_GRAPHIFY_PLUGIN, encoding="utf-8")
241
- created.append(".opencode/plugins/graphify.js")
264
+ # .opencode/plugins/graphify.js — PostToolUse hook (codegraph syncs itself, no hook needed)
265
+ if backend == "graphify":
266
+ plugins_dir = project_dir / ".opencode" / "plugins"
267
+ plugins_dir.mkdir(parents=True, exist_ok=True)
268
+ plugin_path = plugins_dir / "graphify.js"
269
+ if not plugin_path.exists():
270
+ plugin_path.write_text(_OPENCODE_GRAPHIFY_PLUGIN, encoding="utf-8")
271
+ created.append(".opencode/plugins/graphify.js")
242
272
 
243
273
  # opencode.json — MCP server config
244
274
  opencode_json = project_dir / "opencode.json"
@@ -306,7 +336,7 @@ def _check_and_offer_install(tool: str) -> None:
306
336
  console.print(f" [dim]Install manually: {info['install']}[/dim]\n")
307
337
  return
308
338
 
309
- answer = console.input(f" Install {info['name']} now? [y/N] ").strip().lower()
339
+ answer = console.input(f" Install {info['name']} now? {escape('[y/N]')} ").strip().lower()
310
340
  if answer != "y":
311
341
  console.print(f" [dim]Skipping. Install manually: {info['install']}[/dim]\n")
312
342
  return
@@ -323,10 +353,36 @@ def _check_and_offer_install(tool: str) -> None:
323
353
  console.print(f" [red]✗[/red] Install failed. Run manually: {info['install']}\n")
324
354
 
325
355
 
356
+ _GRAPH_BACKENDS = {
357
+ "graphify": "existing default — this scaffolds the PostToolUse hook that auto-updates it",
358
+ "codegraph": "you run `codegraph install && codegraph init` yourself — it syncs itself, no hook needed",
359
+ "none": "skip for now — set either up later, `nexus doctor` will detect it",
360
+ }
361
+
362
+
363
+ def _resolve_graph_backend(explicit: str | None) -> str:
364
+ if explicit:
365
+ if explicit not in _GRAPH_BACKENDS:
366
+ console.print(f" [red]✗[/red] Unknown --graph-backend '{explicit}'. Choose from: {', '.join(_GRAPH_BACKENDS)}")
367
+ raise typer.Exit(1)
368
+ return explicit
369
+
370
+ if not sys.stdin.isatty():
371
+ return "graphify" # unchanged behavior for CI/scripted `nexus init`
372
+
373
+ console.print(" Which knowledge graph do you want nexus to wire up?")
374
+ console.print(" [cyan]1[/cyan] graphify (default)")
375
+ console.print(" [cyan]2[/cyan] codegraph")
376
+ console.print(" [cyan]3[/cyan] skip for now")
377
+ answer = console.input(f" Choice {escape('[1]')}: ").strip()
378
+ return {"2": "codegraph", "3": "none"}.get(answer, "graphify")
379
+
380
+
326
381
  @app.command()
327
382
  def init(
328
383
  project_dir: str = typer.Argument(".", help="Project directory to initialize"),
329
384
  tool: str = typer.Option("claude", "--tool", "-t", help=f"AI coding tool to set up for ({', '.join(_SUPPORTED_TOOLS)})"),
385
+ graph_backend: str = typer.Option(None, "--graph-backend", "-g", help=f"Knowledge graph tool to wire up ({', '.join(_GRAPH_BACKENDS)}). Prompts interactively if omitted."),
330
386
  ) -> None:
331
387
  """Initialize nexus in a project directory. Defaults to Claude Code."""
332
388
  if tool not in _SUPPORTED_TOOLS:
@@ -335,11 +391,13 @@ def init(
335
391
 
336
392
  _check_and_offer_install(tool)
337
393
 
394
+ backend = _resolve_graph_backend(graph_backend)
395
+
338
396
  root = Path(project_dir).resolve()
339
397
  console.print(f" [cyan]▶[/cyan] Initializing nexus for [bold]{tool}[/bold] in [bold]{root}[/bold]\n")
340
398
 
341
399
  if tool == "opencode":
342
- created = _init_opencode(root)
400
+ created = _init_opencode(root, backend)
343
401
  for f in created:
344
402
  console.print(f" [green]✓[/green] {f}")
345
403
  if not created:
@@ -347,7 +405,7 @@ def init(
347
405
  return
348
406
  console.print(f"\n [bold green]Done.[/bold green] Open [bold]{root}[/bold] in OpenCode and type [cyan]/scaffold[/cyan]\n")
349
407
  else:
350
- created = _init_project(root)
408
+ created = _init_project(root, backend)
351
409
  for f in created:
352
410
  console.print(f" [green]✓[/green] {f}")
353
411
  if not created:
@@ -357,32 +415,58 @@ def init(
357
415
  console.print(f" [green]✓[/green] {mcp}")
358
416
  console.print(f"\n [bold green]Done.[/bold green] Open [bold]{root}[/bold] in Claude Code and type [cyan]/scaffold[/cyan]\n")
359
417
 
418
+ if backend == "codegraph":
419
+ console.print(" [cyan]→[/cyan] Next: run [bold]codegraph install && codegraph init[/bold] to wire codegraph into this project (it manages its own auto-sync — no hook needed).\n")
420
+
360
421
 
361
422
  @app.command()
362
- def update() -> None:
423
+ def update(
424
+ also_sync: bool = typer.Option(False, "--sync", "-s", help="Also sync built-in skills/agents in the current directory after upgrading."),
425
+ ) -> None:
363
426
  """Update nexus-dev-toolkit to the latest version."""
364
- console.print("\n [cyan]▶[/cyan] Updating nexus-dev-toolkit…\n")
365
- if shutil.which("uv"):
366
- subprocess.run(["uv", "tool", "upgrade", "nexus-dev-toolkit"])
427
+ latest_version = _fetch_latest_pypi_version()
428
+ if latest_version and not _is_outdated(_VERSION, latest_version):
429
+ console.print(f"\n [green]✓[/green] Already up to date (v{_VERSION}).\n")
367
430
  else:
368
- subprocess.run([sys.executable, "-m", "pip", "install", "--upgrade", "nexus-dev-toolkit"])
369
- console.print("\n [green]✓[/green] Done.\n")
431
+ console.print("\n [cyan]▶[/cyan] Updating nexus-dev-toolkit…\n")
432
+ if shutil.which("uv"):
433
+ subprocess.run(["uv", "tool", "upgrade", "nexus-dev-toolkit"])
434
+ else:
435
+ subprocess.run([sys.executable, "-m", "pip", "install", "--upgrade", "nexus-dev-toolkit"])
436
+ console.print("\n [green]✓[/green] Done.\n")
437
+
438
+ if not also_sync:
439
+ if sys.stdin.isatty():
440
+ answer = console.input(f" Also sync built-in skills/agents in the current directory? {escape('[y/N]')} ").strip().lower()
441
+ also_sync = answer == "y"
442
+
443
+ if not also_sync:
444
+ console.print(
445
+ " [dim]This only updated the nexus CLI itself. Run [/dim][cyan]nexus sync[/cyan][dim] in each "
446
+ "project to pull the updated skills/agents into .claude/ or .opencode/ — or pass "
447
+ "[/dim][cyan]--sync[/cyan][dim] next time to do both at once.[/dim]\n"
448
+ )
449
+ return
370
450
 
451
+ root = Path(".").resolve()
452
+ table = _sync_project(root)
453
+ if table is None:
454
+ console.print(" [yellow]⚠[/yellow] Current directory isn't a nexus project — skipping sync.\n")
455
+ return
371
456
 
372
- @app.command()
373
- def sync(
374
- project_dir: str = typer.Argument(".", help="Project directory to sync"),
375
- ) -> None:
376
- """Sync built-in skills and agents to their latest versions (custom files untouched)."""
377
- root = Path(project_dir).resolve()
457
+ console.print(f" [cyan]▶[/cyan] Syncing built-ins in [bold]{root}[/bold]\n")
458
+ console.print(table)
459
+ console.print()
460
+
461
+
462
+ def _sync_project(root: Path) -> Table | None:
463
+ """Sync built-in skills/agents into root. None if root isn't a nexus project (neither
464
+ .claude/ nor .opencode/ present) — callers decide how to handle that case."""
378
465
  has_claude = (root / ".claude").is_dir()
379
466
  has_opencode = (root / ".opencode").is_dir()
380
467
 
381
468
  if not has_claude and not has_opencode:
382
- console.print(" [red]✗[/red] Not a nexus project. Run [cyan]nexus init[/cyan] first.\n")
383
- raise typer.Exit(1)
384
-
385
- console.print(f"\n [cyan]▶[/cyan] Syncing built-ins in [bold]{root}[/bold]\n")
469
+ return None
386
470
 
387
471
  table = Table(show_header=True, header_style="dim")
388
472
  table.add_column("File")
@@ -452,6 +536,21 @@ def sync(
452
536
  plugin_dst.write_text(_OPENCODE_GRAPHIFY_PLUGIN, encoding="utf-8")
453
537
  table.add_row(".opencode/plugins/graphify.js", "[cyan]updated[/cyan]")
454
538
 
539
+ return table
540
+
541
+
542
+ @app.command()
543
+ def sync(
544
+ project_dir: str = typer.Argument(".", help="Project directory to sync"),
545
+ ) -> None:
546
+ """Sync built-in skills and agents to their latest versions (custom files untouched)."""
547
+ root = Path(project_dir).resolve()
548
+ table = _sync_project(root)
549
+ if table is None:
550
+ console.print(" [red]✗[/red] Not a nexus project. Run [cyan]nexus init[/cyan] first.\n")
551
+ raise typer.Exit(1)
552
+
553
+ console.print(f"\n [cyan]▶[/cyan] Syncing built-ins in [bold]{root}[/bold]\n")
455
554
  console.print(table)
456
555
  console.print()
457
556
 
@@ -480,6 +579,14 @@ def doctor(
480
579
  has_failure = True
481
580
  return f"[red]✗[/red] {msg}"
482
581
 
582
+ # ── nexus ────────────────────────────────────────────────────────────────
583
+ latest_version = _fetch_latest_pypi_version()
584
+ if latest_version:
585
+ if _is_outdated(_VERSION, latest_version):
586
+ table.add_row("nexus-dev-toolkit", warn(f"update available: v{_VERSION} → v{latest_version} (run: nexus update)"))
587
+ else:
588
+ table.add_row("nexus-dev-toolkit", ok(f"up to date (v{_VERSION})"))
589
+
483
590
  # ── Tool ─────────────────────────────────────────────────────────────────
484
591
  has_claude_bin = bool(shutil.which("claude"))
485
592
  has_opencode_bin = bool(shutil.which("opencode"))
@@ -568,16 +675,42 @@ def doctor(
568
675
  else:
569
676
  table.add_row("Knowledge dirs", warn(f"missing: {', '.join(missing_dirs)}"))
570
677
 
571
- # ── graphify ─────────────────────────────────────────────────────────────
572
- has_graphify = bool(shutil.which("graphify"))
678
+ # ── Knowledge graph backends ────────────────────────────────────────────
679
+ has_graphify = graph_backend.backend_installed("graphify")
573
680
  table.add_row("graphify", ok("installed") if has_graphify else warn("not installed — uv tool install graphifyy"))
574
681
 
575
- graph_path = root / "graphify-out" / "graph.json"
576
- if graph_path.exists():
577
- table.add_row("Knowledge graph", ok("graphify-out/graph.json exists"))
682
+ has_codegraph = graph_backend.backend_installed("codegraph")
683
+ table.add_row("codegraph", ok("installed") if has_codegraph else warn("not installed — npm i -g @colbymchenry/codegraph"))
684
+
685
+ graphify_built = graph_backend.graph_exists("graphify", root)
686
+ codegraph_built = graph_backend.graph_exists("codegraph", root)
687
+ override = graph_backend.get_override()
688
+ active = graph_backend.detect_backend(root)
689
+
690
+ if graphify_built and codegraph_built:
691
+ if override in graph_backend.BACKEND_NAMES and graph_backend.graph_exists(override, root):
692
+ reason = f"forced via {graph_backend.ENV_VAR}={override}"
693
+ else:
694
+ reason = "graphify wins ties by default"
695
+ table.add_row("Knowledge graph", warn(f"both graphify and codegraph graphs present — using {active} ({reason})"))
696
+ elif graphify_built or codegraph_built:
697
+ built = "graphify" if graphify_built else "codegraph"
698
+ output = "graphify-out/graph.json" if built == "graphify" else ".codegraph/codegraph.db"
699
+ table.add_row("Knowledge graph", ok(f"{output} exists ({built})"))
578
700
  else:
579
- table.add_row("Knowledge graph", warn("not built — run: graphify ."))
701
+ table.add_row("Knowledge graph", warn("not built — run: graphify . (or codegraph init)"))
580
702
 
703
+ if override and (override not in graph_backend.BACKEND_NAMES or not graph_backend.graph_exists(override, root)):
704
+ table.add_row(
705
+ graph_backend.ENV_VAR,
706
+ warn(f"set to '{override}' but its graph isn't built — ignoring override, run the matching init/build command"),
707
+ )
708
+
709
+ if graph_backend.has_graphify_hook(root) and codegraph_built and active == "codegraph":
710
+ table.add_row("Stale hook", warn("graphify PostToolUse hook present but codegraph is the active backend — harmless no-op, remove manually if unwanted"))
711
+
712
+ console.print()
713
+ console.print(" [dim]Some tools below are alternatives, not companions (e.g. graphify vs codegraph) — nexus flags conflicts here when both are present.[/dim]")
581
714
  console.print()
582
715
  console.print(table)
583
716
  console.print()
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: nexus-dev-toolkit
3
- Version: 3.1.3
3
+ Version: 3.1.4
4
4
  Summary: Developer workflow toolkit for Claude Code — Day 0 scaffold + Day 1 EPAV
5
5
  Author-email: Ronald dela Cruz <rcdelacruz@users.noreply.github.com>
6
6
  License-Expression: MIT
@@ -22,7 +22,7 @@ Dynamic: license-file
22
22
  # nexus-dev-toolkit
23
23
 
24
24
 
25
- Developer workflow toolkit for Claude Code. Gives any team a structured Day 0 scaffold and repeatable Day 1 feature cycle via the EPAV methodology.
25
+ Developer workflow toolkit for Claude Code and OpenCode. Gives any team a structured Day 0 scaffold and repeatable Day 1 feature cycle via the EPAV methodology.
26
26
 
27
27
  **[Documentation](https://nexus.coderstudio.co/docs)**
28
28
 
@@ -70,6 +70,13 @@ uv tool install graphifyy # PyPI package name has double y; command is "graphi
70
70
  graphify install # registers /graphify skill into Claude Code
71
71
  ```
72
72
 
73
+ **codegraph** _(alternative to graphify)_ — a different knowledge-graph tool EPAV skills can use instead. Pick one, not both; `nexus doctor` warns if it finds graphs from both built in the same project.
74
+
75
+ ```bash
76
+ npm i -g @colbymchenry/codegraph
77
+ codegraph install # wires codegraph into Claude Code / OpenCode / etc.
78
+ ```
79
+
73
80
  ### 2. Install nexus-dev-toolkit
74
81
 
75
82
  ```bash
@@ -80,8 +87,9 @@ uv tool install nexus-dev-toolkit
80
87
 
81
88
  ```bash
82
89
  cd my-project
83
- nexus init . # Claude Code (default)
84
- nexus init . --tool opencode # OpenCode
90
+ nexus init . # Claude Code (default), prompts for graphify/codegraph/none
91
+ nexus init . --tool opencode # OpenCode
92
+ nexus init . --graph-backend codegraph # skip the prompt, use codegraph
85
93
  ```
86
94
 
87
95
  ### 4. Place your reference docs
@@ -111,12 +119,13 @@ Open the project in Claude Code and run:
111
119
 
112
120
  ### 6. Build the knowledge graph
113
121
 
114
- After `/scaffold` completes, run in Claude Code:
122
+ After `/scaffold` completes, build whichever backend you chose at init:
115
123
  ```
116
- /graphify .
124
+ /graphify . # if you chose graphify
125
+ codegraph install && codegraph init # if you chose codegraph, run in your terminal
117
126
  ```
118
127
 
119
- This generates `graphify-out/graph.json` — required by all EPAV skills before starting Day 1.
128
+ This generates `graphify-out/graph.json` or `.codegraph/codegraph.db` — EPAV skills use whichever is present, or fall back to full file reads if neither is built yet. Run `nexus doctor` any time to check which backend is active.
120
129
 
121
130
  ---
122
131
 
@@ -138,12 +147,14 @@ Each step is a built-in skill in `.claude/commands/`. Every task starts from the
138
147
 
139
148
  ## What `nexus init` Creates
140
149
 
150
+ `settings.json`/`graphify.js` below are only created if you pick graphify (the default) at the `--graph-backend` prompt. Pick codegraph instead and neither is scaffolded — codegraph wires and syncs itself via `codegraph install && codegraph init`.
151
+
141
152
  **Claude Code** (`nexus init .`):
142
153
  ```
143
154
  .claude/
144
155
  ├── commands/ ← EPAV skills + 5 reviewer skills (/code-review, etc.)
145
156
  ├── agents/ ← 5 reviewer subagents (code-reviewer, database-reviewer, etc.)
146
- └── settings.json ← PostToolUse: graphify auto-updates after every file edit
157
+ └── settings.json ← PostToolUse: graphify auto-updates after every file edit (graphify backend only)
147
158
  knowledge/
148
159
  ├── rules/ ← coding standards, arch decisions
149
160
  ├── patterns/ ← reusable implementation patterns
@@ -158,7 +169,7 @@ knowledge/
158
169
  ├── commands/ ← same EPAV skills + reviewer skills
159
170
  ├── agents/ ← same reviewer subagents (adapted for OpenCode)
160
171
  └── plugins/
161
- └── graphify.js ← tool.execute.after: graphify auto-update
172
+ └── graphify.js ← tool.execute.after: graphify auto-update (graphify backend only)
162
173
  knowledge/ ← same structure
163
174
  opencode.json ← MCP server config
164
175
  ```
@@ -171,7 +182,8 @@ opencode.json ← MCP server config
171
182
  nexus init . # Claude Code — set up .claude/ + knowledge/ + .mcp.json
172
183
  nexus init . --tool opencode # OpenCode — set up .opencode/ + knowledge/ + opencode.json
173
184
  nexus --version # show installed version
174
- nexus update # update to latest version
185
+ nexus update # update the CLI itself; asks whether to also sync in a real terminal
186
+ nexus update --sync # skip the prompt, always sync the current project's skills/agents too
175
187
  nexus sync # sync built-in skills & agents to latest (custom files untouched)
176
188
  nexus doctor # validate project setup
177
189
 
@@ -20,6 +20,7 @@ tools/agents/monitoring-reviewer.md
20
20
  tools/agents/performance-reviewer.md
21
21
  tools/epav/__init__.py
22
22
  tools/epav/arch_ingest.py
23
+ tools/epav/graph_backend.py
23
24
  tools/epav/package_resolver.py
24
25
  tools/epav/project_rules.py
25
26
  tools/epav/task_loader.py
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "nexus-dev-toolkit"
3
- version = "3.1.3"
3
+ version = "3.1.4"
4
4
  description = "Developer workflow toolkit for Claude Code — Day 0 scaffold + Day 1 EPAV"
5
5
  authors = [
6
6
  {name = "Ronald dela Cruz", email = "rcdelacruz@users.noreply.github.com"}