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()raisesNidlErrorwith codenot_runningand 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_PEERCREDon Linux,LOCAL_PEERCREDon macOS). A check that fails isunsafe_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
appclient kind: it can read, draft, preview and apply, but credential commands, such as connecting an account or unlocking credentials, are refused withrequires_owner_action. Those are yours to run, from the CLI or the desktop. - Command names are listed.
CommandNameis aLiteralof the commands an app may run, generated from the core's registry, andCOMMAND_NAMESholds 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
readtoken lists and reads. Anoperatetoken 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.identityhas norootorinstanceNoncefor a remote core, which does not say what names its files; it says the token'sscope.- 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 withinvalid_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.
lendandwithdrawon a remote core fail withunsupportedbefore anything is sent. - The lease is
{accountId, lentAt, expiresAt, lentBy},lentBybeing 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)
| File | Size | Uploaded | Provenance | |
|---|---|---|---|---|
| nidl_client-0.2.0.tar.gz | 29.5 kB | Without provenance | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| 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.