Gym-compatible wrapper for the NornOS Hosted Research API (research.laif2.com).
Project description
nornos-gym
Gym-compatible wrapper for the NornOS Hosted Research API. Pure Python + gymnasium + numpy + requests. No NornOS-internal knowledge required to use.
Status
v0.2.0 — Hosted API + Bearer-Token-Auth + 429-Retry. Skill outputs not yet
integrated into reward (fallback uses feature-deviation-from-mean, see
PRD-NORNOS-CORE-001 §5.4).
Quickstart (Hosted API — researcher path)
pip install nornos-gym
Request an API key from the operator (see docs/onboarding.md), then:
from nornos_gym import NornOSEnv
env = NornOSEnv(
base_url="https://research.laif2.com",
api_key="nornos-research-<your-uuid>",
)
obs, info = env.reset()
for _ in range(100):
action = env.action_space.sample()
obs, reward, terminated, truncated, info = env.step(action)
print(f"reward={reward:.3f} audit={info['auditHash'][:8]}")
env.close()
The client automatically retries with exponential backoff (max 5 attempts)
when the server returns 429 Too Many Requests, respects Retry-After headers,
and applies ±25% jitter to spread retries.
Error handling
from nornos_gym import NornOSEnv, NornOSAuthError, RateLimitError
try:
env = NornOSEnv(base_url="https://research.laif2.com", api_key="...")
obs, info = env.reset()
except NornOSAuthError as e:
print(f"Token issue: {e}") # 401 missing, 403 invalid/revoked
except RateLimitError as e:
print(f"Rate limit persistent after retries: {e}")
Local stack (development)
# 1. Clone repo, then:
docker compose -f docker-compose.research.yml up -d
# 2. Install editable:
pip install -e research/python/
# 3. Run without api_key (local stack has no auth):
python -c "
from nornos_gym import NornOSEnv
env = NornOSEnv(base_url='http://localhost:4400')
obs, info = env.reset()
print(f'entities: {len(info[\"auditHashes\"])}')
env.close()
"
Public API
NornOSEnv(base_url, seed_id, entity_filter)— Gym 0.26+ environmentNornOSMultiAgentEnv(base_url, seed_id, agent_entity_map)— MARL via ThreadPoolExecutorNornOSAdapter— base class for domain-specific feature extraction + reward shaping
Adapter Quickstart
To plug a domain into NornOS, subclass NornOSAdapter:
from nornos_gym import NornOSAdapter
class CircularEconomyAdapter(NornOSAdapter):
def __init__(self):
super().__init__(feature_keys=["material_weight", "recyclability_score", "co2_footprint"])
def compute_reward(self, skill_outputs):
f = skill_outputs.get("features", skill_outputs)
return (1 - float(f.get("recyclability_score", 0.0))) * \
float(f.get("co2_footprint", 0.0))
5-Step recipe:
- Define your domain features as a fixed
feature_keyslist - Write a custom seed JSON under
research/<your-domain>/<name>_seed.jsonwithentityId/entityType/featuresper entity - Add a
COPYline todocker/compose/Dockerfile.event-log-service-researchthat maps your seed into/app/research/seeds/<your-seed-id>.json - Subclass
NornOSAdapter, overridecompute_reward(and optionallyextract_features) with your domain logic - Use the adapter in your training loop alongside
NornOSEnv— seeresearch/adapter-example/run_episode.py
Full spec, anti-patterns, testing template: research/docs/adapter-interface.md.
Run the circular-economy example
docker compose -f docker-compose.research.yml up -d
python research/adapter-example/run_episode.py --seed-id circular-economy-default --steps 100
Output: server-reward (deviation fallback) and adapter-reward (domain logic) side by side, plus top-3 most-problematic products by mean adapter score.
Building a custom adapter
Adapters are pure Python — no NornOS internals, no library touch. Three
hard rules from adapter-interface.md §4:
- Bound your rewards. PPO/DQN assume a stable range; clip to
[0, 1]or[-1, 1]. - Stay stateless. Don't hold per-step state on
self; the adapter is reused across episodes. - Public API only.
from nornos_gym import NornOSAdapteris the only NornOS import allowed. Noapps/maritime, noservices/event-log-service, no internal modules.
Disclaimer
Research-only distribution. Not for clinical, safety-critical, or production
use. The Compose stack ships with hardcoded -insecure tokens that must
never appear in production deployments.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file nornos_gym-0.2.0.tar.gz.
File metadata
- Download URL: nornos_gym-0.2.0.tar.gz
- Upload date:
- Size: 16.4 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.6
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
2bea7654379aa53c21842d48af33ec705036bcc34d574c9fd6d349a6e551659a
|
|
| MD5 |
022405a51fca13a83cbceca6e638bfcc
|
|
| BLAKE2b-256 |
fa56c4088b119c43c8c44096f43ce16f9edb662d24e982a8df635c5a56105306
|
File details
Details for the file nornos_gym-0.2.0-py3-none-any.whl.
File metadata
- Download URL: nornos_gym-0.2.0-py3-none-any.whl
- Upload date:
- Size: 12.7 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.6
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
024252eb3c73e7c5cbd16b4bd0ab36784cee7133cd19a577a19e8a5d5fbc53a6
|
|
| MD5 |
eac6fe2c562087abd7584111e098883e
|
|
| BLAKE2b-256 |
e84025560099ae1f0c17f69f3d06c15ecf8a4126ec007df744b357eb093b63c0
|