Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions docs/reference/commands.md
Original file line number Diff line number Diff line change
Expand Up @@ -161,13 +161,25 @@ If the installed OpenShell version falls outside this range, onboarding exits wi

Build the sandbox image from a custom Dockerfile instead of the stock NemoClaw image.
The entire parent directory of the specified file is used as the Docker build context, so any files your Dockerfile references (scripts, config, etc.) must live alongside it.
Onboarding skips common large directories (`node_modules`, `.git`, `.venv`, and `__pycache__`) while staging this context.
It also skips credential-style files and directories such as `.env*`, `.ssh/`, `.aws/`, `.netrc`, `.npmrc`, `secrets/`, `*.pem`, and `*.key`.
Other build outputs such as `dist/`, `target/`, or `build/` are still included.
If the staged context is larger than 100 MB, onboarding prints a warning before the Docker build starts.
If the directory contains unreadable files (for example, Windows system files visible in WSL), onboarding exits with an error suggesting you move the Dockerfile to a dedicated directory.

```console
$ nemoclaw onboard --from path/to/Dockerfile
```

The file can have any name; if it is not already named `Dockerfile`, onboard copies it to `Dockerfile` inside the staged build context automatically.
To create an isolated build context, create a dedicated directory that contains only the Dockerfile and the files it needs:

```text
build-dir/
├── Dockerfile
└── files-used-by-COPY/
```

All NemoClaw build arguments (`NEMOCLAW_MODEL`, `NEMOCLAW_PROVIDER_KEY`, `NEMOCLAW_INFERENCE_BASE_URL`, etc.) are injected as `ARG` overrides at build time, so declare them in your Dockerfile if you need to reference them.

In non-interactive mode, the path can also be supplied via the `NEMOCLAW_FROM_DOCKERFILE` environment variable.
Expand Down
24 changes: 24 additions & 0 deletions src/lib/onboard-command.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,9 @@ describe("onboard command", () => {
expect(lines.join("\n")).toContain("Usage: nemoclaw onboard");
expect(lines.join("\n")).toContain("--from <Dockerfile>");
expect(lines.join("\n")).toContain("--name <sandbox>");
expect(lines.join("\n")).toContain("Dockerfile's parent directory");
expect(lines.join("\n")).toContain("node_modules, .git, .venv, __pycache__");
expect(lines.join("\n")).toContain(".env*, .ssh, .aws");
expect(lines.join("\n")).toContain("--agent <name>");
expect(lines.join("\n")).toContain("--dangerously-skip-permissions");
});
Expand Down Expand Up @@ -293,6 +296,27 @@ describe("onboard command", () => {
expect(errors.join("\n")).toContain("--from path not found:");
});

it("exits before onboarding when --from points to a directory", async () => {
const runOnboard = vi.fn(async () => {});
const errors: string[] = [];
const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), "nemoclaw-onboard-from-dir-"));

await expect(
runOnboardCommand({
args: ["--from", tmpDir],
noticeAcceptFlag: "--yes-i-accept-third-party-software",
noticeAcceptEnv: "NEMOCLAW_ACCEPT_THIRD_PARTY_SOFTWARE",
env: {},
runOnboard,
error: (message = "") => errors.push(message),
exit: exitWithPrefixedCode,
}),
).rejects.toThrow("exit:1");

expect(runOnboard).not.toHaveBeenCalled();
expect(errors.join("\n")).toContain("--from must point to a Dockerfile:");
});

it("exits with usage on unknown args", () => {
const errors: string[] = [];
expect(() =>
Expand Down
11 changes: 11 additions & 0 deletions src/lib/onboard-command.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,13 @@ function onboardUsageLines(noticeAcceptFlag: string): string[] {
return [
` Usage: nemoclaw onboard [--non-interactive] [--resume | --fresh] [--recreate-sandbox] [--from <Dockerfile>] [--name <sandbox>] [--agent <name>] [--control-ui-port <N>] [--dangerously-skip-permissions] [${noticeAcceptFlag}]`,
"",
" --from <Dockerfile> uses the Dockerfile's parent directory as the Docker build context.",
" Put files referenced by COPY/ADD next to that Dockerfile, or move the Dockerfile into",
" a dedicated build directory to avoid sending unrelated files to Docker.",
" Common large directories are skipped: node_modules, .git, .venv, __pycache__.",
Comment thread
coderabbitai[bot] marked this conversation as resolved.
" Credential-style files and directories such as .env*, .ssh, .aws, .netrc, .npmrc, secrets/, *.pem, and *.key are also skipped.",
" Generated output directories such as dist/, build/, and target/ are still included.",
"",
];
}

Expand Down Expand Up @@ -78,6 +85,10 @@ export function parseOnboardArgs(
error(` --from path not found: ${resolvedFromDockerfile}`);
exit(1);
}
if (!fs.statSync(resolvedFromDockerfile).isFile()) {
error(` --from must point to a Dockerfile: ${resolvedFromDockerfile}`);
exit(1);
}
fromDockerfile = requestedFromDockerfile;
parsedArgs.splice(fromIdx, 2);
}
Expand Down
Loading
Loading