Metadata-Version: 2.4
Name: denden-server
Version: 0.1.14
Summary: Agent to Agent Communication Layer
License-Expression: MIT
Requires-Python: >=3.10
Requires-Dist: grpcio>=1.60
Requires-Dist: protobuf>=4.25
Provides-Extra: dev
Requires-Dist: grpcio-tools>=1.60; extra == 'dev'
Requires-Dist: pytest>=8.0; extra == 'dev'
Description-Content-Type: text/markdown

# Den Den

<p align="center">
  <a href="https://github.com/strawpot/denden/actions/workflows/ci-go.yml?branch=main"><img src="https://img.shields.io/github/actions/workflow/status/strawpot/denden/ci-go.yml?branch=main&label=Go&style=for-the-badge" alt="Go CI"></a>
  <a href="https://github.com/strawpot/denden/actions/workflows/ci-python.yml?branch=main"><img src="https://img.shields.io/github/actions/workflow/status/strawpot/denden/ci-python.yml?branch=main&label=Python&style=for-the-badge" alt="Python CI"></a>
  <a href="LICENSE"><img src="https://img.shields.io/badge/License-MIT-blue.svg?style=for-the-badge" alt="MIT License"></a>
</p>

Agent-to-orchestrator communication layer. A gRPC transport where agents call back to the orchestrator via the `denden` CLI.

```
Orchestrator (Python gRPC server)
  ├── spawns agents as subprocesses
  └── handles ask_user / delegate requests
         ▲
         │ gRPC (localhost)
         │
     denden CLI (Go binary)
       └── called by agents to send requests
```

## Components

| Component | Language | Path |
|---|---|---|
| CLI client | Go | `cli/` |
| Server library | Python | `server/` |
| Protocol | Protobuf | `proto/denden.proto` |

## Quick start

### Install the server

```bash
cd server
pip install -e '.[dev]'
```

### Build the CLI

```bash
cd cli
go build -o denden .
```

### Run the server

```bash
denden-server --verbose
```

### Use the CLI

```bash
# Health check
./cli/denden status

# Ask user a question
./cli/denden send '{
  "askUser": {
    "question": "Which language?",
    "choices": ["Python", "Go", "Rust"]
  }
}'

# Delegate to a sub-agent
./cli/denden send '{
  "delegate": {
    "delegateTo": "implementer",
    "task": {
      "text": "implement auth module",
      "returnFormat": "TEXT"
    }
  }
}'
```

The CLI auto-fills `request_id`, `denden_version`, `trace.created_at`, and trace fields from environment variables.

### Environment variables

| Variable | Default | Description |
|---|---|---|
| `DENDEN_ADDR` | `127.0.0.1:9700` | Server address |
| `DENDEN_AGENT_ID` | | Agent instance ID (set by orchestrator) |
| `DENDEN_PARENT_AGENT_ID` | | Parent agent instance ID |
| `DENDEN_RUN_ID` | | Run ID |
| `DENDEN_TIMEOUT` | `30s` | CLI request timeout |

## Protocol

Single `.proto` file at `proto/denden.proto`. Two RPCs:

- **Send** — dispatches `ask_user` or `delegate` requests (oneof payload)
- **Status** — health check

Response statuses: `OK`, `DENIED`, `ERROR`.

### Regenerate stubs

```bash
make proto
```

Requires `protoc`, `protoc-gen-go`, `protoc-gen-go-grpc`, and `grpcio-tools`.

## Server as a library

```python
from denden import DenDenServer, ok_response
from denden.gen import denden_pb2

server = DenDenServer(addr="127.0.0.1:9700")

def handle_ask_user(request):
    answer = input(request.ask_user.question + " ")
    return ok_response(
        request.request_id,
        ask_user_result=denden_pb2.AskUserResult(text=answer),
    )

def handle_delegate(request):
    # ... run the delegated task ...
    return ok_response(
        request.request_id,
        delegate_result=denden_pb2.DelegateResult(text="done"),
    )

server.on_ask_user(handle_ask_user)
server.on_delegate(handle_delegate)
server.run()
```

### Dynamic modules

The server CLI supports loading modules at startup:

```bash
denden-server --load-module my_custom_module
```

Modules must expose a `module` attribute or `create_module()` function returning a `denden.Module` subclass.

