nexus-dev-toolkit 3.0.0__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 (26) hide show
  1. nexus_dev_toolkit-3.0.0/LICENSE +21 -0
  2. nexus_dev_toolkit-3.0.0/PKG-INFO +170 -0
  3. nexus_dev_toolkit-3.0.0/README.md +150 -0
  4. nexus_dev_toolkit-3.0.0/nexus_cli.py +292 -0
  5. nexus_dev_toolkit-3.0.0/nexus_dev_toolkit.egg-info/PKG-INFO +170 -0
  6. nexus_dev_toolkit-3.0.0/nexus_dev_toolkit.egg-info/SOURCES.txt +24 -0
  7. nexus_dev_toolkit-3.0.0/nexus_dev_toolkit.egg-info/dependency_links.txt +1 -0
  8. nexus_dev_toolkit-3.0.0/nexus_dev_toolkit.egg-info/entry_points.txt +3 -0
  9. nexus_dev_toolkit-3.0.0/nexus_dev_toolkit.egg-info/requires.txt +7 -0
  10. nexus_dev_toolkit-3.0.0/nexus_dev_toolkit.egg-info/top_level.txt +3 -0
  11. nexus_dev_toolkit-3.0.0/nexus_server.py +16 -0
  12. nexus_dev_toolkit-3.0.0/pyproject.toml +48 -0
  13. nexus_dev_toolkit-3.0.0/setup.cfg +4 -0
  14. nexus_dev_toolkit-3.0.0/tools/__init__.py +0 -0
  15. nexus_dev_toolkit-3.0.0/tools/epav/__init__.py +14 -0
  16. nexus_dev_toolkit-3.0.0/tools/epav/arch_ingest.py +124 -0
  17. nexus_dev_toolkit-3.0.0/tools/epav/package_resolver.py +271 -0
  18. nexus_dev_toolkit-3.0.0/tools/epav/project_rules.py +208 -0
  19. nexus_dev_toolkit-3.0.0/tools/epav/skills/__init__.py +0 -0
  20. nexus_dev_toolkit-3.0.0/tools/epav/skills/apply.md +41 -0
  21. nexus_dev_toolkit-3.0.0/tools/epav/skills/epav.md +46 -0
  22. nexus_dev_toolkit-3.0.0/tools/epav/skills/evaluate.md +42 -0
  23. nexus_dev_toolkit-3.0.0/tools/epav/skills/plan.md +46 -0
  24. nexus_dev_toolkit-3.0.0/tools/epav/skills/scaffold.md +249 -0
  25. nexus_dev_toolkit-3.0.0/tools/epav/skills/validate.md +57 -0
  26. nexus_dev_toolkit-3.0.0/tools/epav/task_loader.py +140 -0
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Ronald dela Cruz
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,170 @@
1
+ Metadata-Version: 2.4
2
+ Name: nexus-dev-toolkit
3
+ Version: 3.0.0
4
+ Summary: LLM-agnostic developer workflow toolkit — Day 0 scaffold + Day 1 EPAV
5
+ Author-email: Ronald dela Cruz <rcdelacruz@users.noreply.github.com>
6
+ License-Expression: MIT
7
+ Project-URL: Homepage, https://nexus.coderstudio.co
8
+ Project-URL: Repository, https://github.com/rcdelacruz/nexus-dev-toolkit
9
+ Project-URL: Issues, https://github.com/rcdelacruz/nexus-dev-toolkit/issues
10
+ Requires-Python: >=3.10
11
+ Description-Content-Type: text/markdown
12
+ License-File: LICENSE
13
+ Requires-Dist: mcp[cli]>=1.0.0
14
+ Requires-Dist: typer>=0.12.0
15
+ Requires-Dist: rich>=13.0.0
16
+ Provides-Extra: dev
17
+ Requires-Dist: pytest>=8.0.0; extra == "dev"
18
+ Requires-Dist: pytest-asyncio>=0.23.0; extra == "dev"
19
+ Dynamic: license-file
20
+
21
+ # nexus-dev-toolkit
22
+
23
+ [![PyPI version](https://img.shields.io/pypi/v/nexus-dev-toolkit)](https://pypi.org/project/nexus-dev-toolkit/)
24
+ [![Python](https://img.shields.io/pypi/pyversions/nexus-dev-toolkit)](https://pypi.org/project/nexus-dev-toolkit/)
25
+ [![License: MIT](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE)
26
+
27
+ Developer workflow toolkit for AI-assisted development. Gives any team a structured Day 0 scaffold and repeatable Day 1 feature cycle via the EPAV methodology.
28
+
29
+ ---
30
+
31
+ ## Why
32
+
33
+ Ad-hoc AI prompting doesn't scale. Every dev prompts differently, context drifts, and nobody knows what the AI was told last sprint.
34
+
35
+ `nexus-dev-toolkit` gives your team a single workflow:
36
+
37
+ - **Day 0** — scaffold the project once, production-grade, zero credentials needed
38
+ - **Day 1** — every feature follows the same four steps: evaluate → plan → apply → validate
39
+
40
+ Every skill, every rule, every pattern lives in the project repo — versioned, shared, and enforced.
41
+
42
+ ---
43
+
44
+ ## The Workflow
45
+
46
+ ### Day 0 — `/scaffold` (once per project)
47
+
48
+ ```
49
+ nexus init <project-dir>
50
+ ```
51
+
52
+ Sets up `.claude/commands/`, `.claude/settings.json`, and `knowledge/`. Then in Claude Code:
53
+
54
+ ```
55
+ /scaffold
56
+ ```
57
+
58
+ EVALUATE → PLAN → APPLY → VALIDATE. Produces a production-grade project: correct stack from your arch doc, mock auth, mock data, design system, AGENTS.md — all from your architecture document. Runs with `npm install && npm run dev` (or equivalent) from commit one.
59
+
60
+ ### Day 1 — EPAV (every feature, every sprint)
61
+
62
+ ```
63
+ /evaluate → /plan → /apply → /validate
64
+ ```
65
+
66
+ Each step is a built-in skill in `.claude/commands/`. Every task starts with a row from the dev tasks CSV. Every task ends with acceptance criteria verified.
67
+
68
+ ---
69
+
70
+ ## Install
71
+
72
+ **Requirements:** Python 3.10+, `uv` (recommended) or `pip`
73
+
74
+ ```bash
75
+ # Recommended
76
+ uv tool install nexus-dev-toolkit
77
+
78
+ # Or via pip
79
+ pip install nexus-dev-toolkit
80
+ ```
81
+
82
+ ---
83
+
84
+ ## Quick Start
85
+
86
+ ```bash
87
+ cd my-project
88
+ nexus init .
89
+ ```
90
+
91
+ Then open the project in Claude Code and type `/scaffold`.
92
+
93
+ ---
94
+
95
+ ## Commands
96
+
97
+ ```bash
98
+ nexus init . # set up .claude/commands/ + knowledge/ + .mcp.json
99
+ nexus skill add code-review # create a custom skill in .claude/commands/
100
+ nexus skill list # list all skills
101
+ nexus rule add api-standards # create a rule in knowledge/rules/
102
+ nexus rule list # list all rules
103
+ nexus update # update to latest version
104
+ ```
105
+
106
+ ---
107
+
108
+ ## What `nexus init` Creates
109
+
110
+ ```
111
+ .claude/
112
+ ├── commands/
113
+ │ ├── scaffold.md ← /scaffold — Day 0 one-time setup
114
+ │ ├── evaluate.md ← /evaluate — orient on a task
115
+ │ ├── plan.md ← /plan — blueprint, no code
116
+ │ ├── apply.md ← /apply — implement the plan
117
+ │ ├── validate.md ← /validate — verify acceptance criteria
118
+ │ └── epav.md ← /epav — full cycle guide
119
+ └── settings.json ← PostToolUse hook: graphify auto-updates after every file edit
120
+ knowledge/
121
+ ├── rules/ ← coding standards, arch decisions
122
+ ├── patterns/ ← reusable implementation patterns
123
+ ├── prompts/dev/ ← task prompt templates
124
+ └── retros/ ← retrospective notes
125
+ .mcp.json ← MCP server config
126
+ ```
127
+
128
+ ---
129
+
130
+ ## MCP Server
131
+
132
+ ```json
133
+ {
134
+ "mcpServers": {
135
+ "nexus": {
136
+ "command": "uvx",
137
+ "args": ["--refresh", "--from", "nexus-dev-toolkit", "nexus-mcp"]
138
+ }
139
+ }
140
+ }
141
+ ```
142
+
143
+ `nexus init` writes `.mcp.json` automatically.
144
+
145
+ ### MCP Tools
146
+
147
+ | Tool | Purpose |
148
+ |---|---|
149
+ | `ingest_architecture_doc` | Load arch doc → `knowledge/rules/arch-summary.md` |
150
+ | `load_task` | Load a CSV task row into context |
151
+ | `generate_project_rules` | Generate `AGENTS.md` from arch doc |
152
+ | `resolve_package_versions` | Resolve exact package versions via real package manager |
153
+
154
+ ---
155
+
156
+ ## Custom Skills
157
+
158
+ ```bash
159
+ nexus skill add my-code-review
160
+ # Edit .claude/commands/my-code-review.md
161
+ # Type /my-code-review in Claude Code
162
+ ```
163
+
164
+ Custom skills live alongside built-in skills in `.claude/commands/` — versioned in your repo, shared across the team.
165
+
166
+ ---
167
+
168
+ ## License
169
+
170
+ [MIT](LICENSE)
@@ -0,0 +1,150 @@
1
+ # nexus-dev-toolkit
2
+
3
+ [![PyPI version](https://img.shields.io/pypi/v/nexus-dev-toolkit)](https://pypi.org/project/nexus-dev-toolkit/)
4
+ [![Python](https://img.shields.io/pypi/pyversions/nexus-dev-toolkit)](https://pypi.org/project/nexus-dev-toolkit/)
5
+ [![License: MIT](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE)
6
+
7
+ Developer workflow toolkit for AI-assisted development. Gives any team a structured Day 0 scaffold and repeatable Day 1 feature cycle via the EPAV methodology.
8
+
9
+ ---
10
+
11
+ ## Why
12
+
13
+ Ad-hoc AI prompting doesn't scale. Every dev prompts differently, context drifts, and nobody knows what the AI was told last sprint.
14
+
15
+ `nexus-dev-toolkit` gives your team a single workflow:
16
+
17
+ - **Day 0** — scaffold the project once, production-grade, zero credentials needed
18
+ - **Day 1** — every feature follows the same four steps: evaluate → plan → apply → validate
19
+
20
+ Every skill, every rule, every pattern lives in the project repo — versioned, shared, and enforced.
21
+
22
+ ---
23
+
24
+ ## The Workflow
25
+
26
+ ### Day 0 — `/scaffold` (once per project)
27
+
28
+ ```
29
+ nexus init <project-dir>
30
+ ```
31
+
32
+ Sets up `.claude/commands/`, `.claude/settings.json`, and `knowledge/`. Then in Claude Code:
33
+
34
+ ```
35
+ /scaffold
36
+ ```
37
+
38
+ EVALUATE → PLAN → APPLY → VALIDATE. Produces a production-grade project: correct stack from your arch doc, mock auth, mock data, design system, AGENTS.md — all from your architecture document. Runs with `npm install && npm run dev` (or equivalent) from commit one.
39
+
40
+ ### Day 1 — EPAV (every feature, every sprint)
41
+
42
+ ```
43
+ /evaluate → /plan → /apply → /validate
44
+ ```
45
+
46
+ Each step is a built-in skill in `.claude/commands/`. Every task starts with a row from the dev tasks CSV. Every task ends with acceptance criteria verified.
47
+
48
+ ---
49
+
50
+ ## Install
51
+
52
+ **Requirements:** Python 3.10+, `uv` (recommended) or `pip`
53
+
54
+ ```bash
55
+ # Recommended
56
+ uv tool install nexus-dev-toolkit
57
+
58
+ # Or via pip
59
+ pip install nexus-dev-toolkit
60
+ ```
61
+
62
+ ---
63
+
64
+ ## Quick Start
65
+
66
+ ```bash
67
+ cd my-project
68
+ nexus init .
69
+ ```
70
+
71
+ Then open the project in Claude Code and type `/scaffold`.
72
+
73
+ ---
74
+
75
+ ## Commands
76
+
77
+ ```bash
78
+ nexus init . # set up .claude/commands/ + knowledge/ + .mcp.json
79
+ nexus skill add code-review # create a custom skill in .claude/commands/
80
+ nexus skill list # list all skills
81
+ nexus rule add api-standards # create a rule in knowledge/rules/
82
+ nexus rule list # list all rules
83
+ nexus update # update to latest version
84
+ ```
85
+
86
+ ---
87
+
88
+ ## What `nexus init` Creates
89
+
90
+ ```
91
+ .claude/
92
+ ├── commands/
93
+ │ ├── scaffold.md ← /scaffold — Day 0 one-time setup
94
+ │ ├── evaluate.md ← /evaluate — orient on a task
95
+ │ ├── plan.md ← /plan — blueprint, no code
96
+ │ ├── apply.md ← /apply — implement the plan
97
+ │ ├── validate.md ← /validate — verify acceptance criteria
98
+ │ └── epav.md ← /epav — full cycle guide
99
+ └── settings.json ← PostToolUse hook: graphify auto-updates after every file edit
100
+ knowledge/
101
+ ├── rules/ ← coding standards, arch decisions
102
+ ├── patterns/ ← reusable implementation patterns
103
+ ├── prompts/dev/ ← task prompt templates
104
+ └── retros/ ← retrospective notes
105
+ .mcp.json ← MCP server config
106
+ ```
107
+
108
+ ---
109
+
110
+ ## MCP Server
111
+
112
+ ```json
113
+ {
114
+ "mcpServers": {
115
+ "nexus": {
116
+ "command": "uvx",
117
+ "args": ["--refresh", "--from", "nexus-dev-toolkit", "nexus-mcp"]
118
+ }
119
+ }
120
+ }
121
+ ```
122
+
123
+ `nexus init` writes `.mcp.json` automatically.
124
+
125
+ ### MCP Tools
126
+
127
+ | Tool | Purpose |
128
+ |---|---|
129
+ | `ingest_architecture_doc` | Load arch doc → `knowledge/rules/arch-summary.md` |
130
+ | `load_task` | Load a CSV task row into context |
131
+ | `generate_project_rules` | Generate `AGENTS.md` from arch doc |
132
+ | `resolve_package_versions` | Resolve exact package versions via real package manager |
133
+
134
+ ---
135
+
136
+ ## Custom Skills
137
+
138
+ ```bash
139
+ nexus skill add my-code-review
140
+ # Edit .claude/commands/my-code-review.md
141
+ # Type /my-code-review in Claude Code
142
+ ```
143
+
144
+ Custom skills live alongside built-in skills in `.claude/commands/` — versioned in your repo, shared across the team.
145
+
146
+ ---
147
+
148
+ ## License
149
+
150
+ [MIT](LICENSE)
@@ -0,0 +1,292 @@
1
+ import json
2
+ import shutil
3
+ import subprocess
4
+ import sys
5
+ from pathlib import Path
6
+
7
+ import typer
8
+ from rich.console import Console
9
+ from rich.table import Table
10
+
11
+ app = typer.Typer(name="nexus", no_args_is_help=True, help="nexus-dev-toolkit — LLM-agnostic developer workflow toolkit")
12
+ skill_app = typer.Typer(name="skill", no_args_is_help=True, help="Manage skills in .claude/commands/")
13
+ rule_app = typer.Typer(name="rule", no_args_is_help=True, help="Manage rules in knowledge/rules/")
14
+ app.add_typer(skill_app, name="skill")
15
+ app.add_typer(rule_app, name="rule")
16
+
17
+ console = Console()
18
+
19
+ # ── Built-in skills shipped with the package ──────────────────────────────────
20
+
21
+ _SKILLS_SRC = Path(__file__).parent / "tools" / "epav" / "skills"
22
+
23
+ _BUILTIN_SKILLS = [
24
+ "scaffold.md",
25
+ "evaluate.md",
26
+ "plan.md",
27
+ "apply.md",
28
+ "validate.md",
29
+ "epav.md",
30
+ ]
31
+
32
+ # ── .claude/settings.json ────────────────────────────────────────────────────
33
+
34
+ _CLAUDE_SETTINGS = {
35
+ "hooks": {
36
+ "PostToolUse": [
37
+ {
38
+ "matcher": ".*",
39
+ "hooks": [
40
+ {
41
+ "type": "command",
42
+ "command": "graphify update . --force 2>/dev/null || true"
43
+ }
44
+ ]
45
+ }
46
+ ]
47
+ }
48
+ }
49
+
50
+ # ── knowledge/ scaffold ───────────────────────────────────────────────────────
51
+
52
+ _KNOWLEDGE_DIRS = [
53
+ "knowledge/rules",
54
+ "knowledge/patterns",
55
+ "knowledge/prompts/dev",
56
+ "knowledge/retros",
57
+ ]
58
+
59
+ # ── MCP config ────────────────────────────────────────────────────────────────
60
+
61
+ _MCP_BLOCK = {
62
+ "nexus": {
63
+ "command": "uvx",
64
+ "args": ["--refresh", "--from", "nexus-dev-toolkit", "nexus-mcp"],
65
+ }
66
+ }
67
+
68
+
69
+ def _init_project(project_dir: Path) -> list[str]:
70
+ """
71
+ nexus init — sets up:
72
+ .claude/commands/ ← built-in skills
73
+ .claude/settings.json ← PostToolUse graphify hook
74
+ knowledge/ ← empty scaffold
75
+ """
76
+ created = []
77
+
78
+ # .claude/commands/ — copy built-in skills
79
+ commands_dir = project_dir / ".claude" / "commands"
80
+ commands_dir.mkdir(parents=True, exist_ok=True)
81
+
82
+ for skill_name in _BUILTIN_SKILLS:
83
+ src = _SKILLS_SRC / skill_name
84
+ dest = commands_dir / skill_name
85
+ if src.exists() and not dest.exists():
86
+ shutil.copy2(src, dest)
87
+ created.append(f".claude/commands/{skill_name}")
88
+
89
+ # .claude/settings.json — PostToolUse graphify hook
90
+ settings_path = project_dir / ".claude" / "settings.json"
91
+ if not settings_path.exists():
92
+ settings_path.write_text(json.dumps(_CLAUDE_SETTINGS, indent=2))
93
+ created.append(".claude/settings.json")
94
+
95
+ # knowledge/ scaffold
96
+ for d in _KNOWLEDGE_DIRS:
97
+ target = project_dir / d
98
+ target.mkdir(parents=True, exist_ok=True)
99
+
100
+ return created
101
+
102
+
103
+ def _write_mcp_config(project_dir: Path) -> str:
104
+ mcp_path = project_dir / ".mcp.json"
105
+ existing: dict = {}
106
+ if mcp_path.exists():
107
+ try:
108
+ existing = json.loads(mcp_path.read_text())
109
+ except Exception:
110
+ pass
111
+ existing.setdefault("mcpServers", {}).update(_MCP_BLOCK)
112
+ mcp_path.write_text(json.dumps(existing, indent=2))
113
+ return ".mcp.json"
114
+
115
+
116
+ # ── Commands ──────────────────────────────────────────────────────────────────
117
+
118
+ @app.command()
119
+ def init(
120
+ project_dir: str = typer.Argument(".", help="Project directory to initialize"),
121
+ ) -> None:
122
+ """Initialize .claude/commands/, .claude/settings.json, and knowledge/ in a project."""
123
+ root = Path(project_dir).resolve()
124
+ console.print(f"\n [cyan]▶[/cyan] Initializing nexus in [bold]{root}[/bold]\n")
125
+
126
+ created = _init_project(root)
127
+ for f in created:
128
+ console.print(f" [green]✓[/green] {f}")
129
+
130
+ if not created:
131
+ console.print(" [yellow]·[/yellow] Already initialized — nothing to do")
132
+ return
133
+
134
+ mcp = _write_mcp_config(root)
135
+ console.print(f" [green]✓[/green] {mcp}")
136
+
137
+ console.print(f"\n [bold green]Done.[/bold green] Open [bold]{root}[/bold] in Claude Code and type [cyan]/scaffold[/cyan]\n")
138
+
139
+
140
+ @app.command()
141
+ def update() -> None:
142
+ """Update nexus-dev-toolkit to the latest version."""
143
+ console.print("\n [cyan]▶[/cyan] Updating nexus-dev-toolkit…\n")
144
+ if shutil.which("uv"):
145
+ subprocess.run(["uv", "tool", "upgrade", "nexus-dev-toolkit"])
146
+ else:
147
+ subprocess.run([sys.executable, "-m", "pip", "install", "--upgrade", "nexus-dev-toolkit"])
148
+ console.print("\n [green]✓[/green] Done.\n")
149
+
150
+
151
+ # ── skill subcommands ─────────────────────────────────────────────────────────
152
+
153
+ _SKILL_TEMPLATE = """\
154
+ # /{name}
155
+
156
+ **{name}** — describe what this skill does.
157
+
158
+ ## When to use
159
+
160
+ Describe the trigger or context.
161
+
162
+ ## Steps
163
+
164
+ ### 1 — First step
165
+
166
+ What to do.
167
+
168
+ ### 2 — Second step
169
+
170
+ What to do next.
171
+
172
+ ### 3 — Output
173
+
174
+ What the AI should produce when done.
175
+ """
176
+
177
+
178
+ @skill_app.command("add")
179
+ def skill_add(
180
+ name: str = typer.Argument(..., help="Skill name (e.g. 'code-review')"),
181
+ project_dir: str = typer.Option(".", "--dir", "-d"),
182
+ ) -> None:
183
+ """Create a new skill in .claude/commands/."""
184
+ root = Path(project_dir).resolve()
185
+ dest = root / ".claude" / "commands" / f"{name}.md"
186
+ dest.parent.mkdir(parents=True, exist_ok=True)
187
+
188
+ if dest.exists():
189
+ console.print(f" [yellow]·[/yellow] .claude/commands/{name}.md already exists")
190
+ return
191
+
192
+ dest.write_text(_SKILL_TEMPLATE.format(name=name), encoding="utf-8")
193
+ console.print(f" [green]✓[/green] Created .claude/commands/{name}.md")
194
+ console.print(f" [dim]Edit it and type [cyan]/{name}[/cyan] in Claude Code.[/dim]")
195
+
196
+
197
+ @skill_app.command("list")
198
+ def skill_list(
199
+ project_dir: str = typer.Option(".", "--dir", "-d"),
200
+ ) -> None:
201
+ """List all skills in .claude/commands/."""
202
+ root = Path(project_dir).resolve()
203
+ commands_dir = root / ".claude" / "commands"
204
+
205
+ if not commands_dir.exists():
206
+ console.print(" [yellow]·[/yellow] No .claude/commands/ found. Run [cyan]nexus init[/cyan] first.")
207
+ return
208
+
209
+ skills = sorted(commands_dir.glob("*.md"))
210
+ if not skills:
211
+ console.print(" [yellow]·[/yellow] No skills yet. Run [cyan]nexus skill add <name>[/cyan]")
212
+ return
213
+
214
+ table = Table(show_header=True, header_style="dim")
215
+ table.add_column("Skill", style="cyan")
216
+ table.add_column("Source")
217
+
218
+ builtins = set(_BUILTIN_SKILLS)
219
+ for s in skills:
220
+ source = "built-in" if s.name in builtins else "custom"
221
+ table.add_row(f"/{s.stem}", source)
222
+
223
+ console.print(table)
224
+
225
+
226
+ # ── rule subcommands ──────────────────────────────────────────────────────────
227
+
228
+ _RULE_TEMPLATE = """\
229
+ # {name}
230
+
231
+ _Project rule — read by AI tools via AGENTS.md._
232
+
233
+ ## Rules
234
+
235
+ - Rule one
236
+ - Rule two
237
+ - Rule three
238
+
239
+ ## Rationale
240
+
241
+ Why these rules exist.
242
+ """
243
+
244
+
245
+ @rule_app.command("add")
246
+ def rule_add(
247
+ name: str = typer.Argument(..., help="Rule name (e.g. 'api-standards')"),
248
+ project_dir: str = typer.Option(".", "--dir", "-d"),
249
+ ) -> None:
250
+ """Create a new rule in knowledge/rules/."""
251
+ root = Path(project_dir).resolve()
252
+ dest = root / "knowledge" / "rules" / f"{name}.md"
253
+ dest.parent.mkdir(parents=True, exist_ok=True)
254
+
255
+ if dest.exists():
256
+ console.print(f" [yellow]·[/yellow] knowledge/rules/{name}.md already exists")
257
+ return
258
+
259
+ dest.write_text(_RULE_TEMPLATE.format(name=name), encoding="utf-8")
260
+ console.print(f" [green]✓[/green] Created knowledge/rules/{name}.md")
261
+
262
+
263
+ @rule_app.command("list")
264
+ def rule_list(
265
+ project_dir: str = typer.Option(".", "--dir", "-d"),
266
+ ) -> None:
267
+ """List all rules in knowledge/rules/."""
268
+ root = Path(project_dir).resolve()
269
+ rules_dir = root / "knowledge" / "rules"
270
+
271
+ if not rules_dir.exists():
272
+ console.print(" [yellow]·[/yellow] No knowledge/rules/ found. Run [cyan]nexus init[/cyan] first.")
273
+ return
274
+
275
+ rules = sorted(rules_dir.glob("*.md"))
276
+ if not rules:
277
+ console.print(" [yellow]·[/yellow] No rules yet. Run [cyan]nexus rule add <name>[/cyan]")
278
+ return
279
+
280
+ table = Table(show_header=True, header_style="dim")
281
+ table.add_column("Rule", style="cyan")
282
+ for r in rules:
283
+ table.add_row(r.stem)
284
+ console.print(table)
285
+
286
+
287
+ def main() -> None:
288
+ app()
289
+
290
+
291
+ if __name__ == "__main__":
292
+ main()