A rebrandable, polyglot platform shell for AI asset pipelines — pluggable pipelines, local-or-cloud compute, local|Perforce storage.
Project description
NoiseWeaver
A rebrandable, polyglot platform for AI asset pipelines — the open, generic layer you run around a pipeline. It provides the parts every studio needs and none of the parts that are anyone's secret.
NoiseWeaver contains no pipeline: the stages, recipes, model wiring, and prompts are a plugin
written by whoever uses it. The dependency arrow points one way — plugins import noiseweaver;
noiseweaver never imports a plugin, a specific compute daemon, or a storage backend it merely
orchestrates. That keeps the platform free of proprietary IP and able to stand on its own (and to be
shared between studios).
The four pillars (+ the shell)
| Module | What it is |
|---|---|
noiseweaver.build |
A generic content-addressed staged-build engine over JSON specs — a mini build system: a spec document → a Merkle DAG → CAS staging → variant ledger + tombstones. |
noiseweaver.compute |
A Tool × Platform compute scheduler — what API you speak (ComfyUI, or a plugin's own client) is orthogonal to where it runs (local, RunPod, k8s); placed Kubernetes-style by matching requirements ↔ offers. |
noiseweaver.storage / .cas |
A storage/repo abstraction (local folder | Perforce stream) + an immutable content-addressed store. The pipeline only ever sees a local path. |
noiseweaver.pod |
Pod transport — discover a RunPod's SSH, hold a persistent tunnel, talk to ComfyUI over HTTP, and run a service on a rented pod (PodService). |
noiseweaver.shell / .plugin |
A rebrandable Gradio shell + the small plugin contract that mounts a pipeline into it. |
Everything is pure-Python and fully unit-tested with no daemon, pod, cluster, or Perforce server (70 tests) — the external pieces are injected and faked.
Build engine — noiseweaver.build
A spec is a JSON document ({type, stages: {stage: params}}). The engine knows how to chain, hash,
store, and cache stages into a Merkle DAG where every parameter branch is content-addressed and
cheaply cached; it knows nothing about what the stages do. A plugin injects a Pipeline (the
stage names + per-stage normalizers, recipe versions, etc.) and the executors.
from noiseweaver.build import Spec, SpecFormat, Pipeline, Staging, Index, build
fmt = SpecFormat(suffix=".demo.json") # your on-disk format + a validator
pipe = Pipeline(stages=("gen", "post"), normalize=my_normalize,
recipe_versions={"gen": "g/1"}, artifact_names={"gen": "gen.png"})
spec = Spec.load("proj/thing.demo.json", fmt, root="…")
build(spec, pipe, {"gen": gen_executor, "post": post_executor},
staging=Staging("~/.cache/staging"), index=Index("~/.cache/staging"))
# unchanged stages are cache hits; changing one param recomputes only it + its descendants.
Subclass Spec to bind your format once (so callers keep a clean MySpec.load(path)) — e.g. a
plugin binds its own .<type>.json format + validator + recipe versions in one place.
Compute — noiseweaver.compute
Two orthogonal axes, composed into a Placement = (Tool, Platform, ExecutionMode) the scheduler
resolves Kubernetes-style:
- Tool — the API you speak (
ComfyUIToolHTTP ships built in; a plugin adds its own, e.g. an NDJSON/UDS local-daemon client). Platform-agnostic; one client whether the service is local, on a pod, or in a cluster. - Platform — where it's provisioned and reached (
LocalPlatform,ExternalPlatform,RemotePlatform). Tool-agnostic; RunPod/k8s lifecycle is injected once and shared across tools. - Requirements ↔ Offers — a tool declares
Requirements({os, arch, accelerator, vram}); a platform declaresOffers; the scheduler only places a tool where the offers satisfy it (an MLX tool requires{macos, mlx}so it never schedules off a Mac; a CUDA workload never lands on a Mac). - Execution modes —
SERVICE(a persistent endpoint, many calls) andJOB(submit → result).
from noiseweaver.compute import (
Scheduler, ComfyUITool, LocalPlatform, RemotePlatform, Offers,
ImageRequest, text_to_image,
)
sched = Scheduler(
# ComfyUITool ships with NoiseWeaver; MyLocalDaemonTool is your plugin's own Tool.
tools=[MyLocalDaemonTool(), ComfyUITool()],
platforms=[LocalPlatform(),
RemotePlatform("runpod", Offers("linux", "x86_64", frozenset({"cuda"}), 80),
acquire=my_pod_acquire)],
)
# picks the local daemon for a Mac-hostable weight, else comfyui@runpod — by matching, not branches.
result = text_to_image(sched, ImageRequest(prompt="…", output="/tmp/out.png",
model="flux", variant="flux1-schnell"))
Storage — noiseweaver.storage / noiseweaver.cas
Point each logical repo at a local folder or a Perforce stream; the pipeline only sees a local path
(a synced Perforce stream is a folder), and NoiseWeaver manages the Perforce workspace (client
spec + login) and sync/submit.
from noiseweaver.config import NoiseWeaverConfig
cfg = NoiseWeaverConfig.load() # reads noiseweaver.toml; P4 password from $P4PASSWD
assets = cfg.repo("assets")
assets.ensure_ready() # provisions the p4 client + login (idempotent)
assets.sync() # `p4 sync` (no-op for a local repo)
root = assets.root() # the local path your pipeline reads/writes
assets.submit([root / "new.fbx"], "add new asset")
noiseweaver.cas.CasStore is the immutable, content-addressed blob+manifest store the build engine's
staging is built on (hardlink materialization, safe to back up as a plain folder).
To back a repo with a local, password-protected, checkpoint-backed Perforce server (and how to
fold-back-up Perforce safely with Backblaze), see
docs/perforce-local-server.md.
Pod — noiseweaver.pod
The generic pod transport the compute backends provision onto: discover_endpoint (RunPod GraphQL
direct-SSH), PodSSH (persistent control SSH + local port-forward), ComfyUIClient (HTTP + UI→API
workflow conversion), and PodService — the reusable lifecycle: discover → connect → optional
deploy hook → start a foreground command → forward its port → wait until ready → tear down on close.
Discovery + the SSH class are injectable, so the whole lifecycle unit-tests with no pod.
The shell — noiseweaver.shell / noiseweaver.plugin
from noiseweaver.shell import launch
launch(MyPipelinePlugin(), my_config) # serves the rebranded UI on the LAN
A plugin implements three methods — branding(), build_header(config), tabs(). The shell owns
the chrome; set NOISEWEAVER_TITLE / NOISEWEAVER_SUBTITLE to rebrand without code. See
noiseweaver/plugin.py.
Configuration
noiseweaver.toml (path via NOISEWEAVER_CONFIG) — repos + the compute policy; secrets come from
the environment, never the file. See noiseweaver.example.toml.
[repos.assets]
kind = "perforce" # or "local"
stream = "//assets/main"
client = "assets-mac-you"
root = "~/p4/assets"
[compute]
runpod = true # offload backends available to the scheduler
k8s = false
prefer = ["local", "runpod", "k8s"]
Develop
uv sync --extra dev
uv run pytest # 70 tests, no external services
uv run ruff check
MIT licensed.
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 noiseweaver-0.1.0.tar.gz.
File metadata
- Download URL: noiseweaver-0.1.0.tar.gz
- Upload date:
- Size: 169.3 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
72fbcdc95051fe9cffbbe9e251ef065e0d7024db922e634b6ef5bd39ae8a1d21
|
|
| MD5 |
a298cdbd439e174b4b5721fcff209cc2
|
|
| BLAKE2b-256 |
a2d34a6207c599912e3ecc202b8dcf7be104c00d4190898c06f02d9ccd792d58
|
Provenance
The following attestation bundles were made for noiseweaver-0.1.0.tar.gz:
Publisher:
release.yml on gviot/NoiseWeaver
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
noiseweaver-0.1.0.tar.gz -
Subject digest:
72fbcdc95051fe9cffbbe9e251ef065e0d7024db922e634b6ef5bd39ae8a1d21 - Sigstore transparency entry: 2026761128
- Sigstore integration time:
-
Permalink:
gviot/NoiseWeaver@80bae9fb64ba5d66ce5bbc0c89cb81e47a6ee0eb -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/gviot
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@80bae9fb64ba5d66ce5bbc0c89cb81e47a6ee0eb -
Trigger Event:
push
-
Statement type:
File details
Details for the file noiseweaver-0.1.0-py3-none-any.whl.
File metadata
- Download URL: noiseweaver-0.1.0-py3-none-any.whl
- Upload date:
- Size: 55.6 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
08a3a7223a71c6c93668abf051c4aff0ab6c7f6afe55d91732d8b1ac3cbf8eb2
|
|
| MD5 |
a058c6314bbf64303de79cfe799706b3
|
|
| BLAKE2b-256 |
b9a1d970025149e63d42c39fdb59574e94bdd0bcd48d50fc349f4e622b40125b
|
Provenance
The following attestation bundles were made for noiseweaver-0.1.0-py3-none-any.whl:
Publisher:
release.yml on gviot/NoiseWeaver
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
noiseweaver-0.1.0-py3-none-any.whl -
Subject digest:
08a3a7223a71c6c93668abf051c4aff0ab6c7f6afe55d91732d8b1ac3cbf8eb2 - Sigstore transparency entry: 2026761230
- Sigstore integration time:
-
Permalink:
gviot/NoiseWeaver@80bae9fb64ba5d66ce5bbc0c89cb81e47a6ee0eb -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/gviot
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@80bae9fb64ba5d66ce5bbc0c89cb81e47a6ee0eb -
Trigger Event:
push
-
Statement type: