# Contributing to NVIDIA NemoClaw
Thank you for your interest in contributing to NVIDIA NemoClaw. This guide covers how to set up your development environment, run tests, and submit changes.
## Before You Open an Issue
Open an issue when you encounter one of the following situations.
- A real bug that you confirmed and could not fix.
- A feature proposal with a design — not a "please build this" request.
- Security vulnerabilities must follow [SECURITY.md](SECURITY.md) — **not** GitHub issues.
## Prerequisites
Install the following before you begin.
- Node.js 22.16+ and npm 10+
- Python 3.11+ (for blueprint and documentation builds)
- Docker (running)
- [uv](https://docs.astral.sh/uv/) (for Python dependency management)
- [hadolint](https://github.com/hadolint/hadolint) (Dockerfile linter — `brew install hadolint` on macOS)
## Getting Started
Install the root dependencies and build the TypeScript plugin:
```bash
# Install root dependencies (OpenClaw + CLI entry point)
npm install
# Install and build the TypeScript plugin
cd nemoclaw && npm install && npm run build && cd ..
# Install Python deps for the blueprint
cd nemoclaw-blueprint && uv sync && cd ..
```
## Building
The TypeScript plugin lives in `nemoclaw/` and compiles with `tsc`:
```bash
cd nemoclaw
npm run build # one-time compile
npm run dev # watch mode
```
The CLI (`bin/`, `scripts/`) is type-checked separately:
```bash
npm run typecheck:cli # or: npx tsc -p tsconfig.cli.json
```
### Local Development Testing
After building, return to the repository root and link the CLI so the `nemoclaw` command is available locally.
If you followed the build step above, you are still inside `nemoclaw/` and must `cd ..` first:
```bash
cd .. # back to the repo root (from nemoclaw/ subdirectory)
npm link
nemoclaw --version # verify the linked version
```
To unlink when you are done: `npm unlink -g nemoclaw`
## Main Tasks
These are the primary `make` and `npm` targets for day-to-day development:
| Task | Purpose |
|------|---------|
| `make check` | Run all linters (TypeScript + Python) |
| `make lint` | Same as `make check` |
| `make format` | Auto-format TypeScript and Python source |
| `npm run typecheck:cli` | Type-check CLI TypeScript (`bin/`, `scripts/`) |
| `npm test` | Run root-level tests (`test/*.test.js`) |
| `cd nemoclaw && npm test` | Run plugin unit tests (Vitest) |
| `make docs` | Build documentation (Sphinx/MyST) |
| `make docs-live` | Serve docs locally with auto-rebuild |
| `npx prek run --all-files` | Run all hooks from `.pre-commit-config.yaml` — see below |
### Git hooks (prek)
All git hooks are managed by [prek](https://prek.j178.dev/), a fast, single-binary pre-commit hook runner installed as a devDependency (`@j178/prek`). The `npm install` step runs `prek install` automatically via the `prepare` script, which wires up the following hooks from [`.pre-commit-config.yaml`](.pre-commit-config.yaml):
| Hook | What runs |
|------|-----------|
| **pre-commit** | File fixers, formatters, linters, doc-to-skills regeneration, Vitest (plugin) |
| **commit-msg** | commitlint (Conventional Commits) |
| **pre-push** | TypeScript type check (`tsc --noEmit` for plugin, JS, and CLI) |
For a full manual check: `npx prek run --all-files`. For scoped runs: `npx prek run --from-ref --to-ref HEAD`.
If you still have `core.hooksPath` set from an old Husky setup, Git will ignore `.git/hooks`. Run `git config --unset core.hooksPath` in this repo, then `npm install` so `prek install` (via `prepare`) can register the hooks.
`make check` remains the primary documented linter entry point.
## Project Structure
The repository is organized as follows.
| Path | Purpose |
|------|---------|
| `nemoclaw/` | TypeScript plugin (Commander CLI, OpenClaw extension) |
| `nemoclaw-blueprint/` | Python blueprint for sandbox orchestration |
| `bin/` | CLI entry point (`nemoclaw.js`) |
| `scripts/` | Install helpers and automation scripts |
| `test/` | Root-level integration tests |
| `docs/` | User-facing documentation (Sphinx/MyST) |
## Language Policy
All new source files must be TypeScript. Do not add new `.js` files to the project. When modifying an existing JavaScript file, prefer migrating it to TypeScript in the same PR.
Only a small CommonJS launcher/compatibility layer remains in `bin/`, while the main CLI implementation now lives in `src/lib/` and compiles to `dist/`. Tests in `test/` may remain ESM JavaScript for now but new test files should use TypeScript where practical.
Shell scripts (`scripts/*.sh`) must pass ShellCheck and use `shfmt` formatting.
## Documentation
If your change affects user-facing behavior (new commands, changed defaults, new features, bug fixes that contradict existing docs), update the relevant pages under `docs/` in the same PR.
If you use an AI coding agent (Cursor, Claude Code, Codex, etc.), the repo includes the `nemoclaw-contributor-update-docs` skill that drafts doc updates. Use it before writing from scratch and follow the style guide in [docs/CONTRIBUTING.md](docs/CONTRIBUTING.md).
To build and preview docs locally:
```bash
make docs # build the docs
make docs-live # serve locally with auto-rebuild
```
See [docs/CONTRIBUTING.md](docs/CONTRIBUTING.md) for the full style guide and writing conventions.
### Doc-to-Skills Pipeline
The `docs/` directory is the source of truth for user-facing documentation.
The script `scripts/docs-to-skills.py` converts doc pages into agent skills under `.agents/skills/`.
These generated skills let AI agents answer user questions and walk through procedures without reading raw doc pages.
Always edit pages in `docs/`.
Never edit generated skill files under `.agents/skills/nemoclaw-user-*/` — your changes will be overwritten on the next run.
A pre-commit hook regenerates skills automatically whenever you commit changes to `docs/**/*.md` files. The hook runs `scripts/docs-to-skills.py` and stages the updated skills so they are included in the same commit. No manual step is needed for normal workflows.
To regenerate skills manually (for example, after rebasing or outside of a commit), run from the repo root:
```bash
python scripts/docs-to-skills.py docs/ .agents/skills/ --prefix nemoclaw-user
```
Always use this exact output path (`.agents/skills/`) and prefix (`nemoclaw-user`) so skill names and locations stay consistent.
Preview what would change before writing files:
```bash
python scripts/docs-to-skills.py docs/ .agents/skills/ --prefix nemoclaw-user --dry-run
```
Other useful flags:
| Flag | Purpose |
|------|---------|
| `--strategy ` | Grouping strategy: `smart` (default), `grouped`, or `individual`. |
| `--name-map CAT=NAME` | Override a generated skill name (e.g. `--name-map about=overview`). |
| `--exclude ` | Skip specific files (e.g. `--exclude "release-notes.md"`). |
#### Generated skill structure
Each skill directory contains:
```text
.agents/skills//
├── SKILL.md # Frontmatter + procedures + related skills
└── references/ # Detailed concept and reference content (loaded on demand)
├── .md
└── .md
```
Agents load the `references/` directory only when needed (progressive disclosure).
The `SKILL.md` itself stays under 500 lines so agents can read it quickly.
## Pull Requests
We welcome contributions. Every PR requires maintainer review. To keep the review queue healthy, limit the number of open PRs you have at any time to fewer than 10.
> [!WARNING]
> Accounts that repeatedly exceed this limit or submit automated bulk PRs may have their PRs closed or their access restricted.
### No External Project Links
Do not add links to third-party code repositories, community collections, or unofficial resources in documentation, README files, or code. This includes "awesome lists," community template repositories, wrapper projects, and similar community-maintained resources — regardless of popularity or utility.
Links to official documentation for tools we depend on (e.g., Node.js, Python, uv) and industry standards (e.g., Conventional Commits) are acceptable.
**Why:** External repositories are outside our control. They can change ownership, inject malicious content, or misrepresent an endorsement by NVIDIA. Keeping references within our own repo avoids these risks entirely.
If you believe an external resource belongs in our docs, open an issue to discuss it with maintainers first.
### Submitting a Pull Request
Follow these steps to submit a pull request.
1. Create a feature branch from `main`.
2. Make your changes with tests.
3. Run `make check` and `npm test` to verify.
4. Open a PR.
### Commit Messages
This project uses [Conventional Commits](https://www.conventionalcommits.org/). All commit messages must follow the format:
```text
():
[optional body]
[optional footer(s)]
```
**Types:**
- `feat` - New feature
- `fix` - Bug fix
- `docs` - Documentation only
- `chore` - Maintenance tasks (dependencies, build config)
- `refactor` - Code change that neither fixes a bug nor adds a feature
- `test` - Adding or updating tests
- `ci` - CI/CD changes
- `perf` - Performance improvements
**Examples:**
```text
feat(cli): add --profile flag to nemoclaw onboard
fix(blueprint): handle missing API key gracefully
docs: update quickstart for new install wizard
chore(deps): bump commander to 13.2
```