From 00732c8f438b30771cf17d57da27e8062a677b38 Mon Sep 17 00:00:00 2001 From: groundnuty Date: Sat, 21 Feb 2026 19:05:00 +0100 Subject: [PATCH 1/2] fix(cli): allow hyphens in agent names Relax agentNameRegex to accept hyphens, aligning the Go validator with the database constraint. Dots remain excluded to avoid .well-known URL routing ambiguity. Add PythonSafeName helper to convert hyphens to underscores for Python code generation. Fixes #158 --- .../agent/frameworks/adk/python/generator.go | 4 +++ pkg/validators/names.go | 20 ++++++++---- pkg/validators/names_test.go | 32 ++++++++++++++++--- 3 files changed, 46 insertions(+), 10 deletions(-) diff --git a/internal/cli/agent/frameworks/adk/python/generator.go b/internal/cli/agent/frameworks/adk/python/generator.go index 2e9e473d..3ba39af6 100644 --- a/internal/cli/agent/frameworks/adk/python/generator.go +++ b/internal/cli/agent/frameworks/adk/python/generator.go @@ -8,6 +8,7 @@ import ( "github.com/agentregistry-dev/agentregistry/internal/cli/agent/frameworks/common" "github.com/agentregistry-dev/agentregistry/pkg/models" + "github.com/agentregistry-dev/agentregistry/pkg/validators" ) //go:embed templates/* templates/agent/* templates/mcp_server/* dice-agent-instruction.md @@ -31,6 +32,9 @@ func (g *PythonGenerator) Generate(agentConfig *common.AgentConfig) error { return fmt.Errorf("agent config is required") } + // Convert agent name to Python-safe identifier (hyphens to underscores) + agentConfig.Name = validators.PythonSafeName(agentConfig.Name) + projectPackageDir := filepath.Join(agentConfig.Directory, agentConfig.Name) if err := os.MkdirAll(projectPackageDir, 0o755); err != nil { return fmt.Errorf("failed to create package directory: %w", err) diff --git a/pkg/validators/names.go b/pkg/validators/names.go index d76558df..9df7d095 100644 --- a/pkg/validators/names.go +++ b/pkg/validators/names.go @@ -57,20 +57,22 @@ func ValidateProjectName(name string) error { return nil } -// agentNameRegex enforces the strictest rule - names that work BOTH as Python identifiers AND as publishable agent names. -// Must start with a letter, followed by alphanumeric only, minimum 2 characters. -var agentNameRegex = regexp.MustCompile(`^[a-zA-Z][a-zA-Z0-9]+$`) +// agentNameRegex enforces names that work as publishable agent names. +// Must start with a letter, end with a letter or digit, can contain hyphens in the middle. +// Dots are intentionally excluded to avoid .well-known URL path routing ambiguity. +// Minimum 2 characters. +var agentNameRegex = regexp.MustCompile(`^[a-zA-Z][a-zA-Z0-9-]*[a-zA-Z0-9]$`) // ValidateAgentName checks if the agent name is valid. -// Allowed: letters and digits only, must start with a letter, minimum 2 characters. -// Not allowed: underscores, dots, hyphens, or Python keywords. +// Allowed: letters, digits, and hyphens; must start with a letter, end with a letter or digit. +// Not allowed: underscores, dots, or Python keywords. func ValidateAgentName(name string) error { if name == "" { return fmt.Errorf("agent name cannot be empty") } if !agentNameRegex.MatchString(name) { - return fmt.Errorf("agent name must start with a letter and contain only letters and digits (minimum 2 characters)") + return fmt.Errorf("agent name must start with a letter, end with a letter or digit, and contain only letters, digits, and hyphens (minimum 2 characters)") } // Reject Python keywords to avoid issues in generated code @@ -81,6 +83,12 @@ func ValidateAgentName(name string) error { return nil } +// PythonSafeName converts an agent name to a valid Python identifier +// by replacing hyphens with underscores. +func PythonSafeName(name string) string { + return strings.ReplaceAll(name, "-", "_") +} + // ValidateMCPServerName checks if the MCP server name matches the required format. // Server name must be in format "namespace/name" where: // - namespace: starts/ends with alphanumeric, can contain dots and hyphens, min 2 chars diff --git a/pkg/validators/names_test.go b/pkg/validators/names_test.go index ec74d367..882844ef 100644 --- a/pkg/validators/names_test.go +++ b/pkg/validators/names_test.go @@ -46,23 +46,25 @@ func TestValidateAgentName(t *testing.T) { input string wantErr bool }{ - // Valid cases - letters and digits only, starts with letter, min 2 chars + // Valid cases - starts with letter, ends with letter or digit, min 2 chars {"valid simple", "myagent", false}, {"valid alphanumeric", "agent123", false}, {"valid mixed case", "MyAgent2", false}, {"valid two chars", "ab", false}, + {"valid with hyphen", "my-agent", false}, + {"valid multi-hyphen", "my-cool-agent", false}, - // Invalid - special characters not allowed - {"hyphen not allowed", "my-agent", true}, + // Invalid - special characters not allowed (except hyphens) {"dot not allowed", "my.agent", true}, {"underscore not allowed", "my_agent", true}, {"contains slash", "my/agent", true}, {"contains space", "my agent", true}, - // Invalid - must start with letter + // Invalid - must start with letter, end with letter or digit {"starts with number", "123agent", true}, {"starts with dot", ".agent", true}, {"starts with hyphen", "-agent", true}, + {"trailing hyphen rejected", "agent-", true}, // Invalid - too short {"single char", "a", true}, @@ -149,3 +151,25 @@ func TestValidateSkillName(t *testing.T) { }) } } + +func TestPythonSafeName(t *testing.T) { + tests := []struct { + name string + input string + expected string + }{ + {"converts hyphens", "my-agent", "my_agent"}, + {"no hyphens unchanged", "myagent", "myagent"}, + {"multiple hyphens", "my-cool-agent", "my_cool_agent"}, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + result := PythonSafeName(tt.input) + if result != tt.expected { + t.Errorf("PythonSafeName(%q) = %q, want %q", + tt.input, result, tt.expected) + } + }) + } +} From 507c017336485dae86f8b1c0964c48ef22a676c9 Mon Sep 17 00:00:00 2001 From: groundnuty Date: Wed, 25 Feb 2026 17:46:50 +0100 Subject: [PATCH 2/2] fix(cli): clarify why Python name conversion is needed Expand comment to explain that Python identifiers cannot contain hyphens (parsed as subtraction), which is why agent names must be converted to underscores for the package directory and module name. Signed-off-by: Bartosz Balis --- internal/cli/agent/frameworks/adk/python/generator.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/internal/cli/agent/frameworks/adk/python/generator.go b/internal/cli/agent/frameworks/adk/python/generator.go index 3ba39af6..70b37265 100644 --- a/internal/cli/agent/frameworks/adk/python/generator.go +++ b/internal/cli/agent/frameworks/adk/python/generator.go @@ -32,7 +32,9 @@ func (g *PythonGenerator) Generate(agentConfig *common.AgentConfig) error { return fmt.Errorf("agent config is required") } - // Convert agent name to Python-safe identifier (hyphens to underscores) + // Python identifiers cannot contain hyphens (e.g., "my-agent" is parsed as + // "my minus agent"), so convert to underscores for the package directory and + // module name. agentConfig.Name = validators.PythonSafeName(agentConfig.Name) projectPackageDir := filepath.Join(agentConfig.Directory, agentConfig.Name)