Skip to main content

FlashNode

The open host agent of the FlashML system. Install FlashNode on a machine you own, and it can safely execute distributed ML tasks for the FlashML network — earning contribution credits for verified useful work.

FlashNode is one of three components in the FlashML system by Zolli Labs:

  • flashnode (this repo) — open host agent installed by resource contributors. Because it runs on someone else's machine and executes third-party workloads, it must be inspectable, minimal, and explicit about permissions — which is why it is open source.
  • flashruntime — the open workload protocol and execution layer.
  • flashml-cloud (private) — the managed control plane and dashboard.

Read docs/SYSTEM_OVERVIEW.md for the full product architecture, and AGENTS.md if you are an AI coding agent working in this repo.

Status

Pre-release; the device executor works today (July 2026). A machine with this agent can join a FlashRuntime coordinator over outbound HTTP, pull leased tasks, execute them, relay training checkpoints, and commit verified results. Two profiles:

  • Device profile (flashnode work) — the pull-based executor for laptops/workstations. Implemented.
  • Kubernetes profile (flashnode agent) — per-node telemetry reporter inside managed pools (DaemonSet); KubeRay owns workload pods there. Implemented.

Check your machine first

flashnode doctor

Six checks: the docker CLI, the engine behind it, an anonymous pull of a curated image, whether a container can see your work directory, whether your Docker accepts the sandbox flags, and whether any directories you lend via FLASHNODE_LOCAL_DATA are readable. Every failure names the fix.

Run it once before flashnode work. work repeats all of it except the image pull — a registry blip should not stop an agent whose images are already cached — and refuses to start if anything fails, because a host that cannot run tasks should not be claiming them.

What it does today

pip install -e .                      # plus: pip install -e ../flashruntime
flashnode doctor                      # check this machine can run tasks
flashnode work --coordinator http://<coordinator>:8100
# optional hardening / pool config:
#   FLASHNODE_JOIN_CODE=...          join-code-gated pools
#   --runner docker + FLASHNODE_ALLOWED_IMAGES=img:tag,...   container tier
#   FLASHNODE_WORKDIR=$HOME/.cache/flashnode   (macOS + colima: VM-visible workdirs)
#   FLASHNODE_WORKDIR=C:\Users\<you>\.flashnode  (Windows: must be under a
#                                                 directory Docker Desktop shares)
#   FLASHNODE_LOCAL_DATA=patients=/srv/data/patients-2026,labs=/srv/labs
#                                    lend local directories to tasks by LABEL

FLASHNODE_LOCAL_DATA lets you offer data without uploading it. Only the label names (patients, labs) are advertised to the coordinator — never the paths — and a task that names a label in its local_inputs gets that directory bind-mounted read-only at /work/inputs/<label>. A task asking for a label this machine does not lend is refused, not run half-fed; a task that asks for nothing sees nothing, exactly as before.

If the coordinator enforces per-machine authentication (FLASHML_NODE_TOKENS set server-side), save the bearer token you were given before running work:

flashnode login --coordinator http://<coordinator>:8100 --token <token>
flashnode work --coordinator http://<coordinator>:8100   # reads the saved token automatically
flashnode logout --coordinator http://<coordinator>:8100 # forget it locally (does not revoke server-side)

login/logout write to a per-coordinator credential store at ~/.flashnode/credentials.json (override with FLASHNODE_CREDENTIALS), keyed by coordinator URL so one machine can hold separate tokens for separate pools. The file is written with mode 0600 on every save. A missing or unparseable file is treated as "no saved token" rather than a crash. CoordinatorClient sends the saved token as a bearer header on every request to that coordinator once it's saved — there is nothing else to configure. Token issuance is still manual and out-of-band today (the coordinator operator hands you the token; there is no self-service signup or browser device flow yet), and flashnode logout only removes the local copy — the operator revokes access by removing your token from the coordinator's configuration.

  • Stable node identity; registers with capabilities (CPU, RAM, arch, GPU) and re-registers automatically if the coordinator restarts.
  • Outbound-only HTTP — no inbound ports, no router configuration.
  • Claims task leases, renews them with attempt heartbeats, and stops work the moment a lease is refused (the coordinator's idempotent commit rejects late duplicates regardless — defense in depth).
  • Two execution tiers behind one interface: SubprocessRunner (allowlisted Python modules, wall-clock timeout, scrubbed environment — agent secrets never reach task code) and DockerRunner (allowlisted images, --network none, cpu/memory limits, read-only rootfs, uid mapping).
  • Downloads shared input artifacts; uploads outputs with sha256 for the coordinator's commit-time validation.
  • Checkpoint courier: tasks stay network-isolated, so the agent fetches the task's latest valid checkpoint before a run (resume) and ships each new checkpoint file during it — a task killed on this machine resumes from its checkpoint on another.

Still to come: Ed25519-signed identity, admission benchmarks (benchmark/), richer telemetry (telemetry/), gVisor/Kata isolation tiers, and the join/status/leave UX.

Security contract

  • Outbound-only control connection; no inbound SSH or public ports.
  • Signed node identity; short-lived session credentials.
  • Allowlisted or signed workload images only.
  • Non-root execution; no host Docker socket, device passthrough, or privileged mode.
  • The agent shows exactly which limits and permissions apply to a workload before executing it.
  • Complete event logging of task assignment, image digest, permissions, and artifact commits.

Supported host class (initial): x86-64 Linux, macOS (Docker Desktop or Colima), or Windows (Docker Desktop with the WSL2 backend), Python 3.10+, ≥4 CPU cores, ≥8 GB RAM, stable outbound internet.

Windows note: flashnode work used to crash immediately on Windows (os.getuid/os.getgid don't exist there). It now omits --user on Windows instead, relying on the curated images' own non-root USER declaration for non-root execution — see docs/guides/donate-a-machine.md in flashruntime for the full picture, including honest caveats: Windows support is constructed-argv-verified (tests fake the platform), not yet execution-verified against a real Windows machine.

Package layout

Working today:

flashnode/
├── agent/       # CLI (`work`, `agent`), K8s-profile daemon, kube helper
├── identity/    # stable node ID (Ed25519 signing: planned); credentials.py
│                #   is the per-coordinator bearer-token store behind
│                #   `flashnode login`/`logout`
├── inventory/   # capability discovery (psutil + K8s allocatable)
└── executor/    # the device work cycle:
    ├── client.py         # stdlib outbound HTTP: leases, artifacts, checkpoints
    ├── runner.py         # Tier 1: allowlisted subprocess, scrubbed env
    ├── docker_runner.py  # Tier 2: allowlisted containers, network-none
    └── loop.py           # claim → run (heartbeating) → relay ckpts → commit

Scaffolds awaiting their vertical slice: benchmark/ (admission probes), telemetry/ (rich metrics), artifacts/ (local caching), config/ (host-owner policy).

License

Apache-2.0. Contributions via Developer Certificate of Origin (git commit -s).

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

flashnode-0.3.1.tar.gz (97.4 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

flashnode-0.3.1-py3-none-any.whl (69.0 kB view details)

Uploaded Python 3

File details

Details for the file flashnode-0.3.1.tar.gz.

File metadata

  • Download URL: flashnode-0.3.1.tar.gz
  • Upload date:
  • Size: 97.4 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.14

File hashes

Hashes for flashnode-0.3.1.tar.gz
Algorithm Hash digest
SHA256 70879b80efa4260ed007daff9246d78cb3add8e25b2c29cdabe1fcf40ed3bfab
MD5 ffa1de9a93e2c41b3af5bebdf030d66b
BLAKE2b-256 0f214c29962fd8463f75756026209aa244d7ed5b8473f76febff1667b43e013c

See more details on using hashes here.

Provenance

The following attestation bundles were made for flashnode-0.3.1.tar.gz:

Publisher: release-flashnode.yml on Zolli-Labs/flashml

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file flashnode-0.3.1-py3-none-any.whl.

File metadata

  • Download URL: flashnode-0.3.1-py3-none-any.whl
  • Upload date:
  • Size: 69.0 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.14

File hashes

Hashes for flashnode-0.3.1-py3-none-any.whl
Algorithm Hash digest
SHA256 cd248a0bd860fee9dfcdf9fc4b4598f7c77f8cc0af87b43ce766904d9fab7966
MD5 0225c2867a712ca890d193649713e186
BLAKE2b-256 7bedec979130452f733cf020c0b278c2d6016417aa3a7b4fc0e3a2cc58037079

See more details on using hashes here.

Provenance

The following attestation bundles were made for flashnode-0.3.1-py3-none-any.whl:

Publisher: release-flashnode.yml on Zolli-Labs/flashml

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page