Metadata-Version: 2.4
Name: loop-node
Version: 0.1.0
Summary: Shared Node protocol and runtime for Loop and external integrations.
Requires-Python: >=3.10
Description-Content-Type: text/markdown
Requires-Dist: eclipse-zenoh==1.9.0
Requires-Dist: protobuf>=7.36.0
Requires-Dist: pydantic>=2.12.0
Provides-Extra: numpy
Requires-Dist: numpy>=1.26; extra == "numpy"

# loop-node

`loop-node` is the low-level runtime and wire protocol shared by Loop and
`loop-sdk`. Most integrations should use `loop-sdk` directly; use `loop-node`
when building a lower-level Node API or integration layer.

## Installation

```bash
pip install loop-node
```

Published wheels support CPython 3.10–3.14 on Linux x86_64 (glibc 2.28+).
They contain compiled implementation modules and type stubs; installation
does not require a compiler.

## Minimal example

```python
import time

from loop_node import (
    EmptyConfig,
    FieldContract,
    LifecycleState,
    Node,
    NodeConnectionConfig,
    PayloadContract,
    ValueKind,
)

VALUE = PayloadContract(fields={"value": FieldContract(kind=ValueKind.SCALAR)})

node = Node(config_type=EmptyConfig)
output = node.declare_stream_output("value", payload_contract=VALUE)
node.start(
    node_id="example_node",
    connection=NodeConnectionConfig(loop_endpoint="tcp/127.0.0.1:7448"),
)

try:
    while node.is_running:
        node.process_control()
        if node.status.lifecycle is LifecycleState.ACTIVE:
            output.publish(timestamp_ns=time.time_ns(), payload={"value": 1.0})
        time.sleep(0.1)
finally:
    if node.status.lifecycle is not LifecycleState.FINALIZED:
        node.shutdown()
    node.close()
```

A Node declares its Config and Ports before connecting. Loop supplies the
validated Config, Port bindings, and lifecycle operations.
Call `process_control()` regularly to handle lifecycle requests from Loop.
Use the Node lifecycle state to decide when your application should exchange
Graph data. In most cases, only exchange data while the Node is `ACTIVE`.

## Lifecycle

All Nodes use `IDLE → Configure → CONFIGURED → Start → ACTIVE`.
Configure validates Config and calls optional `on_configure(config)` before
Port binding. Start takes only bindings and calls optional `on_start()`.
Stop and ResetFault return to IDLE; each restart requires Configure again.
Configure may update existing payload contracts. The Orchestrator validates
the resulting graph before starting Nodes. Port names and kinds stay fixed.

Describe returns the Config schema and current Port contracts for inspection.
Loop uses Configure results for payload compatibility checks; contracts read
through Describe are not treated as finalized for a run.
