Skip to content
Open
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
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[project]
name = "uipath"
version = "2.9.11"
version = "2.9.12"
description = "Python SDK and CLI for UiPath Platform, enabling programmatic interaction with automation services, process management, and deployment tools."
readme = { file = "README.md", content-type = "text/markdown" }
requires-python = ">=3.11"
Expand Down
38 changes: 10 additions & 28 deletions src/uipath/_cli/cli_init.py
Original file line number Diff line number Diff line change
Expand Up @@ -117,39 +117,21 @@ def generate_agent_md_file(


def generate_agent_md_files(target_directory: str, no_agents_md_override: bool) -> None:
"""Generate AGENTS.md related files and Claude Code skills.
"""Generate CLAUDE.md file.

Args:
target_directory: The directory where the files should be created.
target_directory: The directory where the file should be created.
no_agents_md_override: Whether to override existing files.
"""
agent_dir = os.path.join(target_directory, ".agent")
os.makedirs(agent_dir, exist_ok=True)
claude_commands_dir = os.path.join(target_directory, ".claude", "commands")
os.makedirs(claude_commands_dir, exist_ok=True)

files_to_create = {
target_directory: ["AGENTS.md", "CLAUDE.md"],
agent_dir: ["CLI_REFERENCE.md", "REQUIRED_STRUCTURE.md", "SDK_REFERENCE.md"],
claude_commands_dir: ["new-agent.md", "eval.md"],
}

any_overridden = False
for directory, filenames in files_to_create.items():
for filename in filenames:
if generate_agent_md_file(directory, filename, no_agents_md_override):
any_overridden = True

if any_overridden:
console.success(
f"Updated {click.style('AGENTS.md', fg='cyan')} files and Claude Code skills."
)
return

console.success(
f"Created {click.style('AGENTS.md', fg='cyan')} files and Claude Code skills."
overridden = generate_agent_md_file(
target_directory, "CLAUDE.md", no_agents_md_override
)

if overridden:
console.success(f"Updated {click.style('CLAUDE.md', fg='cyan')}.")
else:
console.success(f"Created {click.style('CLAUDE.md', fg='cyan')}.")


def write_bindings_file(bindings: Bindings) -> Path:
"""Write bindings to a JSON file.
Expand Down Expand Up @@ -325,7 +307,7 @@ def _display_entrypoint_graphs(entry_point_schemas: list[UiPathRuntimeSchema]) -
is_flag=True,
required=False,
default=False,
help="Won't override existing .agent files and AGENTS.md file.",
help="Won't override existing CLAUDE.md file.",
)
@track_command("initialize")
def init(no_agents_md_override: bool) -> None:
Expand Down
6 changes: 5 additions & 1 deletion src/uipath/_resources/CLAUDE.md
Original file line number Diff line number Diff line change
@@ -1 +1,5 @@
@AGENTS.md
# UiPath Coded Agent Project

This is a UiPath coded agent project using the UiPath Python SDK.

Run with: `uipath run main '{...}'`
104 changes: 45 additions & 59 deletions tests/cli/test_init_agents_md.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
"""Tests for AGENTS.md generation in the init command."""
"""Tests for CLAUDE.md generation in the init command."""

import os
import tempfile
Expand Down Expand Up @@ -28,7 +28,7 @@ def test_generate_agent_md_file_creates_file(self) -> None:
/ "src"
/ "uipath"
/ "_resources"
/ "AGENTS.md"
/ "CLAUDE.md"
)

with (
Expand All @@ -44,25 +44,25 @@ def test_generate_agent_md_file_creates_file(self) -> None:
mock_as_file.return_value.__enter__.return_value = mock_source
mock_as_file.return_value.__exit__.return_value = None

generate_agent_md_file(temp_dir, "AGENTS.md", False)
generate_agent_md_file(temp_dir, "CLAUDE.md", False)

assert (Path(temp_dir) / "AGENTS.md").exists()
assert (Path(temp_dir) / "CLAUDE.md").exists()
finally:
os.chdir(original_cwd)

def test_generate_agents_md_overwrites_existing_file(self) -> None:
"""Test that existing AGENTS.md is overwritten."""
def test_generate_claude_md_overwrites_existing_file(self) -> None:
"""Test that existing CLAUDE.md is overwritten."""
with tempfile.TemporaryDirectory() as temp_dir:
agents_path = Path(temp_dir) / "AGENTS.md"
claude_path = Path(temp_dir) / "CLAUDE.md"
original_content = "Original content"
agents_path.write_text(original_content)
claude_path.write_text(original_content)

mock_source = (
Path(__file__).parent.parent.parent
/ "src"
/ "uipath"
/ "_resources"
/ "AGENTS.md"
/ "CLAUDE.md"
)

with (
Expand All @@ -76,12 +76,12 @@ def test_generate_agents_md_overwrites_existing_file(self) -> None:
mock_as_file.return_value.__enter__.return_value = mock_source
mock_as_file.return_value.__exit__.return_value = None

generate_agent_md_file(temp_dir, "AGENTS.md", False)
generate_agent_md_file(temp_dir, "CLAUDE.md", False)

assert agents_path.read_text() != original_content
assert agents_path.exists()
assert claude_path.read_text() != original_content
assert claude_path.exists()

def test_generate_agents_md_handles_errors_gracefully(self) -> None:
def test_generate_claude_md_handles_errors_gracefully(self) -> None:
"""Test that errors are handled gracefully."""
with tempfile.TemporaryDirectory() as temp_dir:
with (
Expand All @@ -90,19 +90,19 @@ def test_generate_agents_md_handles_errors_gracefully(self) -> None:
):
mock_files.side_effect = RuntimeError("Test error")

generate_agent_md_file(temp_dir, "AGENTS.md", False)
generate_agent_md_file(temp_dir, "CLAUDE.md", False)

mock_console.warning.assert_called_once()
assert "Could not create AGENTS.md: Test error" in str(
assert "Could not create CLAUDE.md: Test error" in str(
mock_console.warning.call_args
)


class TestGenerateAgentMdFiles:
"""Test the generate_agent_md_files function that creates multiple files."""
"""Test the generate_agent_md_files function that creates CLAUDE.md."""

def test_generate_agent_md_files_creates_all_files(self) -> None:
"""Test that all root and agent files are created in the correct locations."""
def test_generate_agent_md_files_creates_claude_md(self) -> None:
"""Test that only CLAUDE.md is created."""
with tempfile.TemporaryDirectory() as temp_dir:
with (
patch("uipath._cli.cli_init.importlib.resources.files") as mock_files,
Expand All @@ -121,30 +121,19 @@ def test_generate_agent_md_files_creates_all_files(self) -> None:

generate_agent_md_files(temp_dir, False)

agent_dir = Path(temp_dir) / ".agent"
assert agent_dir.exists()
assert agent_dir.is_dir()

assert (Path(temp_dir) / "AGENTS.md").exists()
assert (Path(temp_dir) / "CLAUDE.md").exists()

assert (agent_dir / "CLI_REFERENCE.md").exists()
assert (agent_dir / "REQUIRED_STRUCTURE.md").exists()
assert (agent_dir / "SDK_REFERENCE.md").exists()
# Should NOT create .agent directory or AGENTS.md
assert not (Path(temp_dir) / ".agent").exists()
assert not (Path(temp_dir) / "AGENTS.md").exists()
assert not (Path(temp_dir) / ".claude" / "commands").exists()

def test_generate_agent_md_files_overwrites_existing_files(self) -> None:
"""Test that existing files are overwritten."""
def test_generate_agent_md_files_overwrites_existing_claude_md(self) -> None:
"""Test that existing CLAUDE.md is overwritten."""
with tempfile.TemporaryDirectory() as temp_dir:
agent_dir = Path(temp_dir) / ".agent"
agent_dir.mkdir()

agents_path = Path(temp_dir) / "AGENTS.md"
agents_content = "Original AGENTS content"
agents_path.write_text(agents_content)

cli_ref_path = agent_dir / "CLI_REFERENCE.md"
cli_ref_content = "Original CLI_REFERENCE content"
cli_ref_path.write_text(cli_ref_content)
claude_path = Path(temp_dir) / "CLAUDE.md"
claude_content = "Original CLAUDE content"
claude_path.write_text(claude_content)

with (
patch("uipath._cli.cli_init.importlib.resources.files") as mock_files,
Expand All @@ -163,19 +152,17 @@ def test_generate_agent_md_files_overwrites_existing_files(self) -> None:

generate_agent_md_files(temp_dir, False)

assert agents_path.read_text() != agents_content
assert agents_path.read_text() == "Test content"
assert cli_ref_path.read_text() != cli_ref_content
assert cli_ref_path.read_text() == "Test content"
assert claude_path.read_text() != claude_content
assert claude_path.read_text() == "Test content"


class TestInitWithAgentsMd:
"""Test the init command with default AGENTS.md creation."""
class TestInitWithClaudeMd:
"""Test the init command with CLAUDE.md creation."""

def test_init_creates_agent_files_by_default(
def test_init_creates_claude_md_by_default(
self, runner: CliRunner, temp_dir: str
) -> None:
"""Test that agent files are created by default during init."""
"""Test that CLAUDE.md is created by default during init."""
with runner.isolated_filesystem(temp_dir=temp_dir):
# Create a simple Python file
with open("main.py", "w") as f:
Expand All @@ -199,28 +186,27 @@ def test_init_creates_agent_files_by_default(
result = runner.invoke(cli, ["init"])

assert result.exit_code == 0
assert "AGENTS.md" in result.output
assert "file." in result.output
assert "CLAUDE.md" in result.output

assert os.path.exists("AGENTS.md")
assert os.path.exists("CLAUDE.md")

assert os.path.exists(".agent/CLI_REFERENCE.md")
assert os.path.exists(".agent/REQUIRED_STRUCTURE.md")
assert os.path.exists(".agent/SDK_REFERENCE.md")
# Should NOT create .agent directory or AGENTS.md
assert not os.path.exists("AGENTS.md")
assert not os.path.exists(".agent")
assert not os.path.exists(".claude/commands")

def test_init_overwrites_existing_agents_md(
def test_init_overwrites_existing_claude_md(
self, runner: CliRunner, temp_dir: str
) -> None:
"""Test that existing AGENTS.md is overwritten."""
"""Test that existing CLAUDE.md is overwritten."""
with runner.isolated_filesystem(temp_dir=temp_dir):
# Create a simple Python file
with open("main.py", "w") as f:
f.write("def main(input): return input")

# Create existing AGENTS.md
original_content = "Original AGENTS.md content"
with open("AGENTS.md", "w") as f:
# Create existing CLAUDE.md
original_content = "Original CLAUDE.md content"
with open("CLAUDE.md", "w") as f:
f.write(original_content)

temp_source = Path(temp_dir) / "temp_source.md"
Expand All @@ -238,13 +224,13 @@ def test_init_overwrites_existing_agents_md(
mock_as_file.return_value.__enter__.return_value = temp_source
mock_as_file.return_value.__exit__.return_value = None

# Run init (AGENTS.md creation is now default)
# Run init
result = runner.invoke(cli, ["init"])

assert result.exit_code == 0

# Verify content was changed
with open("AGENTS.md", "r") as f:
with open("CLAUDE.md", "r") as f:
content = f.read()
assert content != original_content
assert content == "Test content"