Needle Field Constraints: A Complete Guide to Per-Argument Validation in `needle.Field`

needle.Field supports per-argument constraints including default, required, type, choices, numeric bounds (gt, ge, lt, le), length bounds (min_length, max_length), regex, nullable, and description.

The needle.Field class in the Cactus Compute Needle framework provides declarative validation for tool arguments. When you decorate a function with @tools.tool, each parameter annotated with Field(...) inherits automatic runtime validation powered by Pydantic. This article catalogs every available constraint based on the implementation in needle/agent/tools.py.


Core Constraint Categories

Value Presence and Defaults

Constraint Effect Default
required Argument must be provided explicitly True
default Value used when argument is omitted None
nullable Whether None is an acceptable value False

Use required=False with default to create optional parameters:

from needle.agent import tools

@tools.tool
def fetch_data(
    limit: tools.Field(default=100, required=False, nullable=False)
):
    """Return up to `limit` records."""
    ...

Type Enforcement

The type constraint accepts any Python type or Union of types. Validation occurs during Pydantic model construction:

@tools.tool
def calculate(
    value: tools.Field(type=float),
    count: tools.Field(type=int)
):
    """Process a float value `count` times."""
    ...

Choice-Based Validation

Restrict inputs to an explicit allowlist with choices:

@tools.tool
def set_environment(
    env: tools.Field(choices=["dev", "staging", "production"])
):
    """Select deployment environment."""
    ...

Violation raises ValidationError with a clear message listing permitted values.


Numeric Bounds

Needle provides four comparison operators for number ranges:

Constraint Validates
gt Greater than
ge Greater than or equal
lt Less than
le Less than or equal

Combine multiple constraints for closed or half-open intervals:

@tools.tool
def set_brightness(
    level: tools.Field(type=int, ge=0, le=100)
):
    """Set screen brightness percentage."""
    ...
@tools.tool
def configure_timeout(
    seconds: tools.Field(type=float, gt=0.0, lt=3600.0)
):
    """Set a timeout between 0 and 1 hour (exclusive)."""
    ...

String and Sequence Constraints

Length Bounds

Apply min_length and max_length to any sized collection:

@tools.tool
def create_passcode(
    code: tools.Field(min_length=6, max_length=6)
):
    """Require exactly 6 characters."""
    ...

Regex Pattern Matching

The regex constraint accepts any valid Python regular expression. The match must cover the entire string (implicit ^...$ anchoring):

@tools.tool
def register_device(
    serial: tools.Field(regex=r"[A-Z]{2}-\d{6}")
):
    """Validate serial format like 'AB-123456'."""
    ...

Documentation and Metadata

The description constraint populates generated OpenAPI schemas and tool documentation:

@tools.tool
def search(
    query: tools.Field(description="Search terms for the document index"),
    max_results: tools.Field(
        type=int,
        default=10,
        ge=1,
        le=100,
        description="Maximum number of results to return"
    )
):
    """Perform semantic search across indexed documents."""
    ...

Complete Parameter Example

Combine multiple constraints for robust validation in a single field:

from needle.agent import tools
from typing import Optional

@tools.tool
def send_notification(
    recipient: tools.Field(
        regex=r"^[a-z0-9._%+-]+@[a-z0-9.-]+\.[a-z]{2,}$",
        description="Valid email address"
    ),
    subject: tools.Field(
        min_length=1,
        max_length=200,
        description="Notification subject line"
    ),
    priority: tools.Field(
        default="normal",
        choices=["low", "normal", "high", "urgent"],
        description="Message priority level"
    ),
    retry_count: tools.Field(
        type=int,
        default=3,
        ge=0,
        le=5,
        nullable=False
    ),
    metadata: tools.Field(
        type=Optional[dict],
        default=None,
        nullable=True,
        required=False
    )
):
    """Send a prioritized notification with validation on all fields."""
    ...

Implementation Details

According to the cactus-compute/needle source code, needle.Field is implemented in [needle/agent/tools.py](https://github.com/cactus-compute/needle/blob/main/needle/agent/tools.py). The class constructs a Pydantic FieldInfo object internally, which means:

  • All constraints map directly to Pydantic field parameters
  • Validation errors use Pydantic's standard ValidationError format
  • Type coercion follows Pydantic's strict/lenient mode settings

The tool decorator (exposed via needle/agent/__init__.py) inspects function signatures at decoration time and builds a Pydantic model from Field annotations, enabling runtime validation without boilerplate.


Summary

  • needle.Field accepts 11 distinct constraint parameters: default, required, type, choices, gt, ge, lt, le, min_length, max_length, regex, nullable, and description
  • Constraints compose arbitrarily: combine type with bounds, regex with choices, or any valid combination
  • Validation executes before tool logic runs, guaranteeing clean inputs
  • Implementation leverages Pydantic, ensuring ecosystem compatibility and familiar error messages

Frequently Asked Questions

What happens if multiple constraints conflict in needle.Field?

Pydantic evaluates all constraints simultaneously. A value must satisfy every specified constraint. For example, Field(type=int, ge=0, le=10, choices=[2, 4, 6]) requires an even integer between 0 and 10. Conflicting constraints (like gt=10 with lt=5) create an impossible validation that rejects all inputs.

Does needle.Field support custom validation functions?

The base Field class in needle/agent/tools.py does not expose a validator parameter for arbitrary callables. For complex validation, annotate with Pydantic models directly or wrap the tool function and raise ValueError manually after the standard constraints pass.

How does nullable=True interact with default=None?

Both settings allow None values, but serve different purposes. nullable=True permits explicit None passed by the caller. default=None supplies None when the argument is omitted. Use Field(default=None, nullable=False) to treat "not provided" as None while rejecting explicit None values.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →