Skip to main content

nidl-client

Drive a running nidl core from a Python program, over its local socket, or over HTTPS to its remote port on another machine.

import nidl_client

nidl = nidl_client.connect()  # the core serving ~/.nidl; or connect("/path/to/data")
if nidl.has("targets.list"):
    targets = nidl.command("targets.list")
  • It never starts a core. When none is running, connect() raises NidlError with code not_running and says how to start one: nidl serve --data-dir ~/.nidl, or open the nidl app.
  • It checks the socket before trusting it: each folder on the way is yours or root's and not writable by others, the control folder is 0700, the core's record is a private file describing this folder's core, the socket is the one that record names, and the process at the other end runs as you (SO_PEERCRED on Linux, LOCAL_PEERCRED on macOS). A check that fails is unsafe_folder. Python's standard library cannot read ACLs; the Rust library checks those too.
  • It is an app, not the owner. It connects as the app client kind: it can read, draft, preview and apply, but credential commands, such as connecting an account or unlocking credentials, are refused with requires_owner_action. Those are yours to run, from the CLI or the desktop.
  • Command names are listed. CommandName is a Literal of the commands an app may run, generated from the core's registry, and COMMAND_NAMES holds them. command() is annotated with it, so a type checker flags a misspelled or refused name. At run time any string goes to the core, so a newer core's command still works. Results are plain JSON.
  • Each call is one connection: the folder is checked, the core says hello, the command runs, the connection closes.

NidlError has code for programs, message for people, and outcome: not_started, or unknown when the connection was lost after the command was sent, since it may have run. The codes: not_running, unsafe_folder, not_offered, version_conflict, path_too_long, timeout, protocol_error, or the core's own, such as not_found or requires_owner_action.

A core on another machine

When a machine's owner has turned on nidl's remote port there (nidl remote enable) and issued you a remote token (nidl remote-tokens issue), connect to that core by its URL, https://HOST:PORT:

nidl = nidl_client.connect(
    url="https://nidl.example:8443",
    token=os.environ["NIDL_TOKEN"],
    fingerprint="sha256:...",  # as `nidl remote status` shows it on that machine
)
  • The certificate is checked before the token is sent. With a fingerprint, only nidl's own certificate with that fingerprint is accepted, as SSH remembers a host's key; the handshake still proves the server holds its key. Without one, the certificate must be one the system trusts for the URL's host, as when the owner serves a certificate of their own. Anything else fails with untrusted_certificate, and nothing is sent.
  • The token's scope decides what runs. A read token lists and reads. An operate token also drafts targets, refreshes catalogs and readings, and previews and applies routing. Neither runs credential commands or starts paid model checks: those stay with the owner at the machine (requires_owner_action).
  • nidl.identity has no root or instanceNonce for a remote core, which does not say what names its files; it says the token's scope.
  • Each call is one HTTPS connection to the remote port, closed after the answer.

The remote codes, beside those above: unauthorized (the token is unknown, revoked or expired), untrusted_certificate (the certificate is not the one expected; nothing was sent), throttled (too many failed attempts from this address; wait a minute), invalid_input (the URL, token or fingerprint is malformed, or the command is over 1 MiB), unavailable (the machine could not be reached, or its core is busy or not serving), and unsupported (that nidl's remote port takes no commands; update it there).

Lending your project's key, and reporting readings

Another program can use nidl for its own accounts once the owner has made it a project there (nidl projects create), with a borrowed account for each API key it holds (nidl projects add-account, mode borrowed) and an API target with an app token (nidl targets create, nidl app-tokens issue). Your program lends nidl its key for as long as it wants requests to the target's endpoint, /h/<target>/v1/…, routed with it, and takes it back:

lease = nidl.lend(account_id, api_key, app_token=os.environ["NIDL_APP_TOKEN"], expires_in_seconds=3600)
# ... calls to the target's endpoint route with the key while the lease lives ...
nidl.withdraw(account_id)
  • The key travels in the socket's secret frame, never in a command's arguments, so command("pools.lend") is refused with invalid_input. nidl keeps it in memory only, never on disk, for 60 seconds to 12 hours (an hour unless you say) and never past the app token. It is dropped when the lease expires, when you withdraw it, when the owner revokes the token or removes its target, and when the core stops. Lend again to renew it.
  • The app token proves the account is your project's. A token of another project's target, a revoked or expired one, or none, is refused with not_authorized.
  • On this machine only. lend and withdraw on a remote core fail with unsupported before anything is sent.
  • The lease is {accountId, lentAt, expiresAt, lentBy}, lentBy being your app token's id. It never holds the key.

Python cannot wipe the str you pass in; the frame's own bytes are overwritten once sent.

An observed account is one nidl never holds a key for, a subscription for instance, whose quota your program reports so the owner sees it beside their own:

nidl.observe(account_id, [{"key": "five_hour", "percent": 37.5, "resetsAt": "2026-10-21T15:00:00Z"}])

At most 16 windows, each a key, a percent from 0 to 100, and optionally a label and a resetsAt, captured within the last 24 hours (now, unless you say). On a remote core this needs an operate token bound to your project (nidl remote-tokens issue with its project).

Long-running commands return an operation id: poll it with nidl.command("operations.get", {"operationId": ...}).

The protocol is described in docs/protocol/nidl-core-protocol.md. Python 3.9 or later, macOS or Linux, standard library only: the remote port uses ssl and http.client.

Metadata

Release files for nidl-client 0.2.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for nidl-client 0.2.0
File Size Uploaded Provenance
nidl_client-0.2.0.tar.gz 29.5 kB Without provenance Details

Built distribution (wheel)

Table of built distributions (wheels) for nidl-client 0.2.0
File Interpreter ABI Platform
nidl_client-0.2.0-py3-none-any.whl Python 3 none any Details

Total release size: 52.0 kB

Release files / nidl_client-0.2.0.tar.gz

Download URL nidl_client-0.2.0.tar.gz
Size 29.5 kB
Tags Source
SHA-256 checksum
How to use checksums
9c33a1a0279012c5bf76ed4c0cbd229efe9b448a918545e1d1f9e68abcbd7282
BLAKE2b-256 checksum
How to use checksums
91ede7c4c28c8a229915f1a613176d8a3b1c80f3f09d42e2889719908da27ca9
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.14.7

Release files / nidl_client-0.2.0-py3-none-any.whl

Download URL nidl_client-0.2.0-py3-none-any.whl
Size 22.6 kB
Tags Python 3
SHA-256 checksum
How to use checksums
36e0c26e2af27e647c875f374490c022c35e82678f602145eeb25995fd28368c
BLAKE2b-256 checksum
How to use checksums
16bdb3416be3921a5f70e3f95bf8cff450e0f5a98404d66013fb3c29065c9179
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.14.7

Security for nidl-client 0.2.0

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Release history Release notifications | RSS feed

This release

0.2.0 This release

2 release files No provenance

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page