# Needle.Field Constraint Types: Complete Guide to JSON-Schema Validation in Python

> Explore needle.Field constraint types for robust JSON-Schema validation in Python. Learn about numeric, string, array, and value restriction validators.

- Repository: [Cactus Compute, Inc./needle](https://github.com/cactus-compute/needle)
- Tags: deep-dive
- Published: 2026-08-14

---

**`needle.Field` supports 15+ constraint types including numeric bounds (`ge`, `le`, `gt`, `lt`), string validators (`min_length`, `max_length`, `pattern`, `format`), array constraints (`min_items`, `max_items`, `unique_items`), and value restrictions (`enum`, `const`, `multiple_of`).**

The `Field` class in [cactus-compute/needle](https://github.com/cactus-compute/needle) provides a lightweight, declarative way to attach JSON-Schema validation rules to function parameters when building AI tool interfaces. By mapping Python keyword arguments directly to schema keywords, it enables precise runtime validation without manual schema construction.

## Needle.Field Constraint Types Explained

`needle.Field` is defined in [`needle/agent/tools.py`](https://github.com/cactus-compute/needle/blob/main/needle/agent/tools.py) and accepts constraint parameters that translate 1:1 with JSON-Schema validation keywords. The `apply` method (lines 35-48) handles the conversion from Python arguments to schema-compatible dictionaries.

### Value and Metadata Constraints

These constraints control default values and basic documentation:

- **`default`** — Fallback value used when the parameter is not supplied.
- **`description`** — Human-readable explanation of the field's purpose.
- **`enum`** — Restricts input to a predefined set of literal values.
- **`const`** — Enforces a single constant value the field must equal.

These map to `default`, `description`, `enum`, and `const` JSON-Schema keywords respectively.

### Numeric Range Constraints

For `int` and `float` parameters, `needle.Field` supports four boundary types (lines 19-21):

| Constraint | JSON-Schema Key | Meaning |
|------------|----------------|---------|
| `ge` | `minimum` | Inclusive minimum (≥) |
| `le` | `maximum` | Inclusive maximum (≤) |
| `gt` | `exclusiveMinimum` | Exclusive minimum (>) |
| `lt` | `exclusiveMaximum` | Exclusive maximum (<) |
| `multiple_of` | `multipleOf` | Value must be divisible by this number |

### String Validation Constraints

String parameters accept length and pattern controls (lines 28-30):

- **`min_length`** / **`max_length`** — Inclusive character count bounds.
- **`pattern`** — Regular expression the string must match.
- **`format`** — Semantic format hint (e.g., `"email"`, `"date-time"`, `"uri"`).

### Array Constraints

For list parameters, `needle.Field` provides collection-level validation:

- **`min_items`** / **`max_items`** — Bounds on array element count.
- **`unique_items`** — Boolean requiring all array elements to be distinct.

## Practical Examples

### Basic Numeric Constraints with Defaults

```python
from needle import tool, Field

@tool
def generate(
    temperature: float = Field(default=0.7, ge=0, le=1, description="Sampling temperature"),
    max_tokens: int = Field(default=256, ge=1, le=1024),
    top_p: float = Field(default=1.0, gt=0, le=1)
):
    """Generate text with controlled randomness."""
    return model.generate(temperature=temperature, max_tokens=max_tokens)

```

This example demonstrates **inclusive bounds** (`ge`, `le`) for closed ranges and **exclusive bounds** (`gt`) for open lower limits. The `description` parameter feeds directly into tool documentation.

### String Pattern and Length Validation

```python
from needle import tool, Field
import re

@tool
def extract_email(
    query: str = Field(
        min_length=5,
        max_length=1000,
        pattern=r"^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$",
        format="email",
        description="User email address to verify"
    )
):
    """Extract and validate an email from input."""
    return {"email": query.lower().strip()}

```

The `pattern` constraint accepts raw regex strings. The `format` keyword provides semantic hints to LLM callers without enforcing runtime validation.

### Enumeration with typing.Annotated

When you cannot use `Field` as a default value (e.g., for required parameters), combine it with `typing.Annotated`:

```python
from typing import Annotated
from needle import tool, Field

@tool
def classify_sentiment(
    text: str,
    label: Annotated[
        str,
        Field(enum=["positive", "negative", "neutral"], description="Sentiment category")
    ],
    confidence: Annotated[
        float,
        Field(ge=0, le=1, multiple_of=0.01, description="Confidence score rounded to 2 decimals")
    ]
):
    """Classify text sentiment with constrained output."""
    return {"label": label, "confidence": round(confidence, 2)}

```

Here `enum` restricts `label` to three allowed strings, while `multiple_of` enforces centesimal precision on the confidence score.

### Array Validation

```python
from typing import List
from needle import tool, Field

@tool
def tag_document(
    doc_id: str,
    tags: Field(
        default_factory=list,
        min_items=1,
        max_items=10,
        unique_items=True,
        description="Unique topic tags for the document"
    )
):
    """Apply 1-10 unique tags to a document."""
    return {"doc_id": doc_id, "tags": list(set(tags))}

```

**Note:** `default_factory` allows mutable defaults. The `unique_items` constraint maps to JSON-Schema's `uniqueItems` boolean.

## How Constraints Map to JSON-Schema

The `apply` method in [`needle/agent/tools.py`](https://github.com/cactus-compute/needle/blob/main/needle/agent/tools.py) (lines 35-48) performs the translation. Key mappings include:

| Python Parameter | JSON-Schema Output |
|------------------|-------------------|
| `ge=0` | `"minimum": 0` |
| `gt=0` | `"exclusiveMinimum": 0` |
| `le=1` | `"maximum": 1` |
| `lt=1` | `"exclusiveMaximum": 1` |
| `multiple_of=5` | `"multipleOf": 5` |
| `min_length=10` | `"minLength": 10` |
| `pattern=r"^\d+$"` | `"pattern": "^\\d+$"` |
| `format="date"` | `"format": "date"` |
| `enum=["a", "b"]` | `"enum": ["a", "b"]` |
| `const="fixed"` | `"const": "fixed"` |

This translation ensures compatibility with OpenAI function calling and other JSON-Schema-based tool specifications.

## Combining Multiple Constraints

`needle.Field` constraints are composable. You can apply numeric, string, and metadata constraints simultaneously where logically consistent:

```python
from needle import tool, Field

@tool
def configure_api(
    endpoint: Field(
        default="https://api.example.com",
        min_length=10,
        max_length=2048,
        pattern=r"^https?://",
        format="uri",
        description="HTTPS endpoint URL"
    ),
    retries: Field(default=3, ge=0, le=10, multiple_of=1),
    timeout_ms: Field(default=5000, ge=100, le=60000, multiple_of=100)
):
    """Configure API connection parameters."""
    pass

```

## Summary

- **`needle.Field`** supports **15 constraint types** spanning numeric bounds, string validation, array restrictions, and value controls.
- Constraints map **directly to JSON-Schema keywords** via the `apply` method in [`needle/agent/tools.py`](https://github.com/cactus-compute/needle/blob/main/needle/agent/tools.py).
- Use `default` for optional parameters or **`typing.Annotated`** for required parameters with constraints.
- Numeric bounds use `ge`/`le` (inclusive) and `gt`/`lt` (exclusive) following Python's `functools` naming convention.
- String constraints include length bounds, regex `pattern`, and semantic `format` hints.

## Frequently Asked Questions

### What is the difference between `ge`/`le` and `gt`/`lt` in needle.Field?

`ge` (greater than or equal) and `le` (less than or equal) set **inclusive** bounds that include the endpoint values. `gt` (greater than) and `lt` (less than) set **exclusive** bounds that exclude the endpoint. For example, `Field(ge=0, le=1)` allows 0.0 and 1.0, while `Field(gt=0, lt=1)` allows only values strictly between them.

### Can I use needle.Field without a default value?

Yes. Use `typing.Annotated` to attach `Field` constraints to required parameters: `param: Annotated[type, Field(ge=0)]`. This pattern is necessary when you want validation rules but no default, or when the parameter has no natural default value.

### What JSON-Schema format values does needle.Field accept?

The `format` parameter accepts any string recognized by JSON-Schema including `"date-time"`, `"date"`, `"time"`, `"email"`, `"hostname"`, `"ipv4"`, `"ipv6"`, `"uri"`, and `"uuid"`. Format validation behavior depends on the consuming schema validator—Needle passes the value through to the generated schema without enforcement.

### Does needle.Field validate values at runtime?

`needle.Field` itself only **describes** constraints for schema generation. Actual runtime validation depends on the tool execution environment consuming the schema. The Needle framework uses these schemas for LLM tool binding; strict runtime validation requires additional enforcement by the caller or a JSON-Schema validator.