# Nexus Python SDK - Claude Development Context

## Project Overview

This is the **Nexus Python SDK** (`nexus-rpc` on PyPI), an SDK for implementing Nexus RPC services and handlers in Python.

**Status**: Experimental release stage. Backwards-incompatible changes are anticipated until stable release.

**Key Links**:
- [Nexus RPC Specification](https://github.com/nexus-rpc/api/blob/main/SPEC.md)
- [Nexus Organization](https://github.com/nexus-rpc/)

## Critical Development Rules

### Always Use `uv`

**IMPORTANT**: This project uses `uv` for all Python-related operations. Always prefix Python commands with `uv run`:

```bash
# Running tests
uv run pytest

# Running linters
poe lint

# Formatting
poe format

# Installing dependencies
uv add <package>
uv sync
```

### Always ask permission before adding a dependency

The project should be kept to minimal dependencies. Ask for a review before adding a dependency and include justification for why the dependency must be introduced.

### Task Runner (poethepoet)

The project uses `poethepoet` (poe) for common tasks defined in `pyproject.toml`:

```bash
# Lint everything (basedpyright, pyright, mypy, ruff)
poe lint

# Format code (ruff)
poe format

# Generate documentation
poe docs
```

## Project Structure

```
nexus-rpc/
├── src/nexusrpc/              # Main SDK source code
│   ├── __init__.py            # Public API exports
│   ├── _common.py             # Common types and utilities
│   ├── _serializer.py         # Serialization logic
│   ├── _service.py            # Service definition decorators
│   ├── _util.py               # Internal utilities
│   └── handler/               # Handler implementation
│       ├── __init__.py        # Handler API exports
│       ├── _common.py         # Handler-specific types
│       ├── _core.py           # Core handler logic
│       ├── _decorators.py     # Operation decorators
│       ├── _operation_handler.py  # Operation handler base classes
│       ├── _syncio.py         # Sync/async utilities
│       └── _util.py           # Handler utilities
├── tests/                     # Test suite
│   └── handler/               # Handler tests
├── pyproject.toml             # Project configuration
├── uv.lock                    # Locked dependencies
└── README.md                  # User-facing documentation
```

## Python Configuration

- **Python Version**: >=3.10
- **Type Checkers**: basedpyright (primary), pyright, mypy
- **Linter/Formatter**: ruff
- **Test Framework**: pytest with pytest-asyncio, pytest-cov, pytest-pretty
- **Dependencies**: typing-extensions (runtime), minimal dependencies by design

## Development Workflow

### Running Tests

```bash
# Run all tests
uv run pytest

# Run with coverage
uv run pytest --cov=src/nexusrpc --cov-report=html

# Run specific test file
uv run pytest tests/handler/test_middleware.py

# Run tests matching pattern
uv run pytest -k "test_sync_operation"
```

### Type Checking

The project uses **three** type checkers with specific configurations:

```bash
# Run all type checkers
poe lint

# Individual type checkers
uv run basedpyright
uv run pyright
uv run mypy --check-untyped-defs src
```

Type checking configuration is in `pyproject.toml` under `[tool.pyright]` and `[tool.mypy]`.

### Code Formatting

```bash
# Check formatting
uv run ruff format --check

# Apply formatting
uv run ruff format

# Check imports
uv run ruff check --select I

# Fix imports
uv run ruff check --select I --fix
```

### Linting Workflow

Before committing, always run:
```bash
poe format
poe lint
uv run pytest
```

## Nexus RPC Protocol Summary

### Core Concepts

Nexus is a **synchronous RPC protocol** for arbitrary-duration operations:
- **Caller** invokes a **handler**
- Handler responds **synchronously** (inline) or **asynchronously** (with operation token)
- Async operations support cancellation, state queries, and callbacks

### Operation Addressing

Operations are addressed by:
- **Endpoint URL prefix**: Base URL of the handler
- **Service name**: e.g., `payments.v1` (URL-encodable)
- **Operation name**: e.g., `charge` (URL-encodable)
- **Operation token**: Handler-assigned ID (HTTP header-safe characters)

### Key HTTP Endpoints

#### Start Operation
```
POST /{service}/{operation}?callback={url}
```
- **Query Parameters**: `callback` (optional) for async completion notification
- **Headers**: `Nexus-Callback-*` headers forwarded to callback
- **Returns**:
  - `200 OK`: Synchronous success with result
  - `201 Created`: Async operation started (includes `OperationInfo`)
  - `424 Failed Dependency`: Operation failed or canceled

#### Cancel Operation
```
POST /{service}/{operation}/cancel
```
- **Headers**: `Nexus-Operation-Token` (or `token` query param)
- **Returns**: `202 Accepted`

### Response Types

**OperationInfo**:
```json
{
  "token": "unique-operation-id",
  "state": "succeeded" | "failed" | "canceled" | "running"
}
```

**Failure**:
```json
{
  "message": "Error description",
  "stackTrace": "Optional stack trace",
  "metadata": { "key": "value" },
  "details": "Additional details",
  "cause": { /* nested Failure */ }
}
```

### Standard Error Codes

Map to HTTP status codes:
- `400`: Bad Request
- `401`: Unauthenticated
- `403`: Unauthorized
- `404`: Not Found
- `408`: Request Timeout
- `409`: Conflict
- `429`: Resource Exhausted
- `500`: Internal
- `501`: Not Implemented
- `503`: Unavailable
- `520`: Upstream Timeout

### Important Headers

- `Nexus-Link`: Associates resources (HTTP Link format)
- `Request-Timeout`: Single request timeout (e.g., "5s")
- `Operation-Timeout`: Acceptable operation duration
- `Nexus-Operation-Token`: Operation identifier
- `Nexus-Operation-Start-Time`: Operation start timestamp
- `Nexus-Operation-Close-Time`: Operation completion timestamp (RFC 3339 with ms precision)
- `Nexus-Operation-State`: Final operation state

## SDK Usage Patterns

### Defining a Service

```python
import nexusrpc
from dataclasses import dataclass

@dataclass
class MyInput:
    name: str

@dataclass
class MyOutput:
    message: str

@nexusrpc.service
class MyNexusService:
    my_operation: nexusrpc.Operation[MyInput, MyOutput]
```

### Implementing a Handler

```python
@nexusrpc.handler.service_handler(service=MyNexusService)
class MyNexusServiceHandler:
    # Synchronous operation (returns result immediately)
    @nexusrpc.handler.sync_operation
    async def my_operation(
        self,
        ctx: nexusrpc.handler.StartOperationContext,
        input: MyInput
    ) -> MyOutput:
        return MyOutput(message=f"Hello {input.name}!")

    # Asynchronous operation (returns token, completes later)
    @nexusrpc.handler.async_operation
    async def my_async_operation(
        self,
        ctx: nexusrpc.handler.StartOperationContext,
        input: MyInput,
        start_options: nexusrpc.handler.StartOperationOptions,
    ) -> nexusrpc.handler.OperationReference:
        # Start long-running operation
        operation_id = await start_background_task(input)
        return nexusrpc.handler.OperationReference(token=operation_id)
```

## Code Conventions

### Naming Conventions

- **Public API**: Exported from `nexusrpc/__init__.py` and `nexusrpc/handler/__init__.py`
- **Private modules**: Prefixed with `_` (e.g., `_common.py`, `_util.py`)
- **Classes**: PascalCase (e.g., `StartOperationContext`)
- **Functions/methods**: snake_case (e.g., `sync_operation`, `start_operation`)
- **Type variables**: PascalCase with descriptive names (e.g., `InputType`, `OutputType`)

### Module Organization

- `_common.py`: Shared types, dataclasses, protocols
- `_util.py`: Internal utility functions
- `_decorators.py`: Decorator implementations
- `_core.py`: Core business logic
- `__init__.py`: Public API surface (explicit `__all__` exports)

### Type Annotations

- **Always** use type annotations for public APIs
- Use `typing_extensions` for compatibility (e.g., `Self`, `override`)
- Prefer protocols over abstract base classes
- Use generics for operation types: `Operation[Input, Output]`

### Testing

- Test files mirror source structure: `tests/handler/` for `src/nexusrpc/handler/`
- Use `pytest-asyncio` for async tests
- Prefer integration tests over unit tests where appropriate
- Test both sync and async operation handlers

### Documentation

- Use Google-style docstrings (configured in pydoctor)
- Generate docs with: `uv run poe docs`
- Keep README.md user-focused
- Internal implementation details in comments, not docstrings

## Common Pitfalls

1. **Forgetting `uv run`**: Always prefix Python commands with `uv run`
2. **Type checker differences**: Code must pass all three type checkers (basedpyright, pyright, mypy)
3. **Async/sync mixing**: Be careful with operation handler types (sync vs async operations)
4. **Import organization**: Use `ruff check --select I --fix` to organize imports
5. **Backwards compatibility**: This is experimental; breaking changes are acceptable

## Git Workflow

- **Main branch**: `main`
- **Current branch**: Check with `git branch --show-current`
- Commit messages should be descriptive
- Run `uv run poe lint` and `uv run pytest` before pushing

## Additional Resources

- **PyPI Package**: `nexus-rpc` (note: v1.x despite experimental status)
- **License**: MIT
- **Authors**: Temporal Technologies
- **Python Support**: 3.10+

## Quick Reference Commands

```bash
# Setup
uv sync                           # Install dependencies

# Development
uv run pytest                     # Run tests
uv run poe lint                   # Lint everything
uv run poe format                 # Format code

# Type checking
uv run basedpyright              # Primary type checker
uv run pyright                   # Secondary type checker
uv run mypy --check-untyped-defs src  # Third type checker

# Documentation
uv run poe docs                  # Generate API docs

# Package management
uv add <package>                 # Add dependency
uv add --dev <package>           # Add dev dependency
```

---

**Last Updated**: 2026-01-09
