Skip to main content

Research-grade experiment tracking SDK. Local-first; ships to the Siliconworm dashboard when configured.

Project description

siliconworm — Python SDK

PyPI version Python versions CI License: MIT

The official client for the Siliconworm experiment tracker. Drop-in for wandb-style code, but stays local-first: metrics are always written to ~/.siliconworm/runs/<id>/ and only optionally shipped to a remote ingest endpoint.

Install

pip install siliconworm                # core, zero required deps
pip install "siliconworm[torch]"       # adds torch tensor auto-coercion
pip install "siliconworm[mlx]"         # adds MLX (Apple Silicon) coercion
pip install "siliconworm[numpy]"       # adds numpy scalar auto-coercion
pip install "siliconworm[all]"         # all of the above

Source install:

git clone https://github.com/aryan-shubh/siliconworm
cd siliconworm/sdk/python
pip install -e .

30-second tour

import siliconworm as sw

run = sw.init(
    project="viscount-lm",
    config={"lr": 3e-4, "batch_size": 512, "optimizer": "muon"},
)

for step, batch in enumerate(loader):
    loss = model.step(batch)
    run.log({"train_loss": loss, "lr": sched.lr}, step=step)

run.summary["final_acc"] = acc
run.finish()

That's it. No login, no project setup, no dashboard required. The run record lives at ~/.siliconworm/runs/<id>/:

metrics.jsonl   # one JSON object per .log() call
summary.json    # final aggregates + run metadata
config.json     # hyperparameters as passed to init()
system.json    # host, python, git, gpu snapshot

What's captured automatically

On init() the SDK snapshots:

  • git — current sha, branch, dirty flag, remote
  • python — version, executable, implementation
  • host — user, hostname, OS
  • process — argv, cwd, pid
  • gpu — if torch.cuda.is_available(), each device's name, compute capability, total memory, CUDA + torch versions

This goes to system.json once at start. Nothing is sent over the network unless you opt in.

Optional: ship to a Siliconworm server

If SILICONWORM_API_URL is set, every batch is POSTed to:

POST  <SILICONWORM_API_URL>/v1/runs                       # init payload
POST  <SILICONWORM_API_URL>/v1/runs/<id>/metrics          # ndjson batch
POST  <SILICONWORM_API_URL>/v1/runs/<id>/summary          # full summary
POST  <SILICONWORM_API_URL>/v1/runs/<id>/finish           # end-of-run

Auth via SILICONWORM_API_KEYAuthorization: Bearer …. Failures are swallowed after a couple of retries — the local jsonl is always the source of truth, so a flaky network never loses a step.

API surface

run = siliconworm.init(
    project="…",          # required
    name=None,            # auto-generated "wise-yak-042" if omitted
    config={},           # any JSON-serialisable hyperparameters
    tags=[],
    group=None,
    notes=None,
    job_type=None,
    dir=None,             # override base output dir
    api_url=None,         # else read from SILICONWORM_API_URL
    api_key=None,         # else read from SILICONWORM_API_KEY
)

run.log({"metric": value, }, step=None)   # step auto-increments if None
run.summary["final_acc"] = 0.987           # writes summary.json eagerly
run.finish(exit_code=0)

The bare module also exposes siliconworm.log(...) / siliconworm.finish() that dispatch to the most recent init() — handy when threading a run object through your code is awkward.

Tensor coercion

run.log({"loss": tensor}) does the right thing for torch, numpy, and mlx: 0-d arrays become .item(), nd arrays become .mean().item(). No need to call .item() yourself — and the SDK doesn't import any of those libraries unless you actually pass one in.

Internally this goes through a per-type dispatch cache, so after the first call for a given type the cost is a single dict lookup. Logging at 10k calls/s is comfortable from Python.

Context manager

with siliconworm.init(project="foo") as run:
    for step in range(N):
        run.log({"loss": loss}, step=step)
# finish() is called automatically; exceptions are recorded as summary._error.

Examples

Status

Alpha. The wire protocol may change before 0.2; pin siliconworm==0.1.* if you depend on it.

Releasing (maintainers)

The build + publish flow is driven by uv and PyPI Trusted Publishing — no API tokens stored anywhere.

One-time setup, on pypi.org/manage/account/publishing:

  • PyPI Project Name: siliconworm
  • Owner: aryan-shubh
  • Repository name: siliconworm
  • Workflow filename: publish-python.yml
  • Environment name: pypi (repeat at test.pypi.org with env testpypi)

Then, for each release:

  1. Bump siliconworm/version.py and add a CHANGELOG.md entry.

  2. Open a PR. CI runs uv build + twine check --strict + a smoke test.

  3. After merge, draft a GitHub release with tag sdk-python-vX.Y.Z (e.g. sdk-python-v0.1.0). Publishing the release triggers .github/workflows/publish-python.yml, which runs:

    uv build
    uv publish           # OIDC-authenticated, no token needed
    

Local dry-runs (uses an API token you set as UV_PUBLISH_TOKEN):

cd sdk/python
uv build
uv publish --index testpypi              # → TestPyPI
uv publish                               # → PyPI (don't do this casually)

You can also dress-rehearse the GitHub flow without touching real PyPI: Actions tab → Publish Python SDKRun workflowtarget: testpypi.

License

MIT. See LICENSE.

Project details


Download files

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

Source Distribution

siliconworm-0.2.0.tar.gz (18.6 kB view details)

Uploaded Source

Built Distribution

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

siliconworm-0.2.0-py3-none-any.whl (15.9 kB view details)

Uploaded Python 3

File details

Details for the file siliconworm-0.2.0.tar.gz.

File metadata

  • Download URL: siliconworm-0.2.0.tar.gz
  • Upload date:
  • Size: 18.6 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: uv/0.11.18 {"installer":{"name":"uv","version":"0.11.18","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

File hashes

Hashes for siliconworm-0.2.0.tar.gz
Algorithm Hash digest
SHA256 66ffa6ba715848612c2caa4de8b77abc6cf1cc227e4b824640e2b8ab152291df
MD5 d3d61fae7214230e691dace93c2234e4
BLAKE2b-256 52b47724685736ef2f5c38edb89a57e08b8a62713ffa8c3f3d535ec75e016209

See more details on using hashes here.

File details

Details for the file siliconworm-0.2.0-py3-none-any.whl.

File metadata

  • Download URL: siliconworm-0.2.0-py3-none-any.whl
  • Upload date:
  • Size: 15.9 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: uv/0.11.18 {"installer":{"name":"uv","version":"0.11.18","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

File hashes

Hashes for siliconworm-0.2.0-py3-none-any.whl
Algorithm Hash digest
SHA256 ca0aa58abe9d22daae023beba04341b95a534c692aaa1ad9d9f8cc07c9fc0648
MD5 77d7f4e7f6ad235c2c6defd2f91e5642
BLAKE2b-256 9ddafdb934e52b795d1654675f27ddde3f600d54810e66bdea3de318a47e8a2a

See more details on using hashes here.

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