Skip to content
Draft
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
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
# SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
# SPDX-License-Identifier: Apache-2.0

"""Generic agent installer for Agent Skills-compatible folders."""

from pathlib import Path

import yaml
from nemo_platform_ext.cli.commands.skills.base import Scope, Skill
from nemo_platform_ext.cli.commands.skills.installer import BaseAgentInstaller


class GenericInstaller(BaseAgentInstaller):
name = "generic"
display_name = "Generic (.agents/skills)"
supported_scopes = [Scope.PROJECT, Scope.USER]

def get_install_path(self, scope: Scope, project_root: Path, skill_name: str) -> Path:
if scope == Scope.PROJECT:
return project_root / ".agents" / "skills" / f"nemo-{skill_name}" / "SKILL.md"
return Path.home() / ".agents" / "skills" / f"nemo-{skill_name}" / "SKILL.md"

def format_content(self, skill: Skill) -> str:
front_matter = yaml.safe_dump(
{"name": f"nemo-{skill.name}", "description": skill.description},
sort_keys=False,
allow_unicode=True,
)
return f"---\n{front_matter}---\n\n{skill.content}"
Original file line number Diff line number Diff line change
Expand Up @@ -268,6 +268,20 @@ def install(
bool,
typer.Option("--user", help="Install to user scope (default: project scope)"),
] = False,
project_root: Annotated[
Path | None,
typer.Option(
"--project-root",
help=(
"Override the project root for project-scope installs. Defaults to "
"the nearest ancestor containing a .git directory, or the current "
"working directory if no Git root is found."
),
file_okay=False,
dir_okay=True,
exists=True,
),
] = None,
) -> None:
"""Install Nemo skill files for an AI coding agent.

Expand All @@ -278,6 +292,7 @@ def install(
nemo skills install --agent claude
nemo skills install --agent claude --user
nemo skills install --agent claude --skill inference
nemo skills install --agent generic --project-root path/to/agent
"""
try:
installer = get_installer(agent)
Expand All @@ -295,9 +310,16 @@ def install(
)
raise typer.Exit(code=1)

if project_root is not None and scope is not Scope.PROJECT:
typer.echo(
"Error: --project-root only applies to project-scope installs (omit --user).",
err=True,
)
raise typer.Exit(code=1)

skills = _resolve_skills(skill)
project_root = _find_project_root()
result_paths = installer.install(scope, project_root, skills)
resolved_root = project_root.resolve() if project_root is not None else _find_project_root()
result_paths = installer.install(scope, resolved_root, skills)
typer.echo(f"Installed {len(skills)} skill(s) for {installer.display_name}:")
for path in result_paths:
typer.echo(f" {path}")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
from nemo_platform_ext.cli.commands.skills.agents.claude import ClaudeInstaller
from nemo_platform_ext.cli.commands.skills.agents.codex import CodexInstaller
from nemo_platform_ext.cli.commands.skills.agents.cursor import CursorInstaller
from nemo_platform_ext.cli.commands.skills.agents.generic import GenericInstaller
from nemo_platform_ext.cli.commands.skills.agents.opencode import OpenCodeInstaller
from nemo_platform_ext.cli.commands.skills.base import Skill
from nemo_platform_ext.cli.commands.skills.installer import BaseAgentInstaller
Expand All @@ -42,6 +43,7 @@
"claude": ClaudeInstaller(),
"cursor": CursorInstaller(),
"codex": CodexInstaller(),
"generic": GenericInstaller(),
"opencode": OpenCodeInstaller(),
}

Expand Down
10 changes: 10 additions & 0 deletions plugins/nemo-agents/examples/nemo-cli-agent/AGENTS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# NeMo CLI Agent

You are a NeMo Platform CLI assistant.

Help the user understand and operate NeMo Platform through natural language.

## Skills

If you do not see any NeMo-related skills, install them with
`nemo skills install --agent generic` from this folder.
29 changes: 29 additions & 0 deletions plugins/nemo-agents/examples/nemo-cli-agent/DEEP_AGENTS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
# DeepAgents Runtime

These instructions apply when this folder is run through the bundled
LangChain DeepAgents graph.

## Skills

The runtime loads `.agents/skills/` with DeepAgents `SkillsMiddleware`. It
injects every skill's name, description, and path into this prompt in an
**Available Skills** section.

For every user request, scan **Available Skills** first. If a skill matches the
intent, even loosely, call `read_file` on that skill's `SKILL.md` path before
running any `nemo` command.

## Tools

Use `nemo_cli` only for a single command whose first token is `nemo`. It cannot
run shell pipelines, redirection, `echo`, `cat`, `&&`, or local file creation.
When an instruction shows unsupported shell syntax, adapt it to an equivalent
single `nemo` command.

Do not claim tools are insufficient until you have attempted reasonable
equivalent operations with valid `nemo_cli` commands.

The `write_file` tool defaults to an in-memory scratchpad that subprocess tools,
including `nemo_cli`, cannot read. When a file you create needs to be read by a
subprocess, write it under `/tmp/` and reference that same `/tmp/...` path from
the subprocess.
45 changes: 45 additions & 0 deletions plugins/nemo-agents/examples/nemo-cli-agent/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
# NeMo CLI Agent

`nemo-cli-agent` is a proof-of-concept NeMo Platform reference agent. It uses a NAT wrapper around a DeepAgents graph to help users operate NeMo Platform through natural language and the `nemo` CLI.

## Invoke

```bash
export NEMO_DEFAULT_INFERENCE_BASE_URL=https://inference-api.nvidia.com/v1
export NEMO_DEFAULT_INFERENCE_API_KEY=nvapi-...
export NEMO_DEFAULT_MODEL=nvidia/nvidia/nemotron-3-super-v3
```

The workflow reads these variables from `nemo-cli-agent.yml` and passes them to
NAT's OpenAI-compatible LLM provider.

The fastest path is the bundled `nemo ask` shortcut:

```bash
nemo ask "load the nemo cli skills"
nemo ask "list all my workspaces"
```

`nemo ask` is registered as a top-level command via the `nemo.cli` plugin hook and dispatches to this example agent.

Or run via the standard agent invocation from the repository root:

```bash
nemo agents invoke \
--agent-config plugins/nemo-agents/examples/nemo-cli-agent/nemo-cli-agent.yml \
--input "list all my workspaces"
```

On first run, the DeepAgents runtime installs the NeMo CLI skills into `.agents/skills/`. `AGENTS.md` stays portable for Cursor and other harnesses; `DEEP_AGENTS.md` adds the runtime-specific instructions for the bundled LangChain DeepAgents graph.

Or register it as a platform-managed agent:

```bash
nemo agents create \
--name nemo-cli-agent \
--agent-config plugins/nemo-agents/examples/nemo-cli-agent/nemo-cli-agent.yml
nemo agents deploy --agent nemo-cli-agent
nemo agents invoke --agent nemo-cli-agent --input "show me what is running"
```

Operations that call the Platform API still require the local platform to be running and inference to be configured.
30 changes: 30 additions & 0 deletions plugins/nemo-agents/examples/nemo-cli-agent/nemo-cli-agent.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# NeMo CLI Agent
#
# A DeepAgents workflow for operating NeMo Platform through the `nemo` CLI.
#
# Try it locally:
# nemo agents invoke \
# --agent-config plugins/nemo-agents/examples/nemo-cli-agent/nemo-cli-agent.yml \
# --input "load the nemo cli skills"
# nemo agents invoke \
# --agent-config plugins/nemo-agents/examples/nemo-cli-agent/nemo-cli-agent.yml \
# --input "list all my workspaces"
#
# Or deploy it:
# nemo agents create --name nemo-cli-agent \
# --agent-config plugins/nemo-agents/examples/nemo-cli-agent/nemo-cli-agent.yml
# nemo agents deploy --agent nemo-cli-agent
# nemo agents invoke --agent nemo-cli-agent --input "Create a workspace called demo"

llms:
agent:
_type: openai
base_url: ${NEMO_DEFAULT_INFERENCE_BASE_URL}
api_key: ${NEMO_DEFAULT_INFERENCE_API_KEY}
model_name: ${NEMO_DEFAULT_MODEL}

workflow:
# Generic wrapper for current NAT/LangGraph compatibility gaps.
_type: nat_compatible_langgraph_wrapper
graph: nemo_cli_agent.agent:create_nemo_cli_agent
description: NeMo Platform CLI assistant using LangChain Deep Agents
Loading
Loading