Simultaneous Production, Integration, and Control Environment: an agent harness for coding repositories.
Project description
spice
Simultaneous Production, Integration, and Control Environment.
spice has two axioms: the agent's transcript is the single source of truth, and the repo's filesystem is the single channel of steering. Everything else — supervision, coordination, conscience, hygiene, task routing, and git pressure — is derived mechanically from those two surfaces. The operator does not hand-write a spec; they steer the loop until observed behavior and evolving intent converge.
Operator steering arrives in the live stream; an assistant ACK retires the exact inbox key from the durable filesystem queue.
Three ideas
Semantic ACK
Reading steering is not delivery. An inbox item retires only when the agent
acknowledges it by key in assistant prose — an ACK to accept and record what
changed, or a NACK to refuse with a reason — so the transcript records what was
understood and which durable steering item closed. These keyed markers are cheap,
tool-call-like jump points in the stream, and the vocabulary is meant to grow as
more such keywords prove useful.
Cheap-wrong conscience
Cheap implementation also makes precisely-wrong work cheap. spice turns its style and workflow opinions into a conscience: maxims judge assistant prose as it streams, violations become ordinary inbox steering, and the loop corrects drift while the agent is still working.
Git shadow
Agents work inside a per-process git shadow that routes their upstream view through the local worktree while leaving the operator's own git config alone. Sync belongs to task boundaries, so the agent mostly sees content conflicts and the operator keeps normal repository semantics.
Command table
| Surface | Command | What it does |
|---|---|---|
| Install | spice init / spice dev doctor |
Writes local hooks, materializes the worktree skill, prepares state, and verifies drivers, backends, and policy. |
| Command surface | spice agent run -- <cmd> |
Runs shell commands with RTK rewrite routing, configured wrapper groups, and steering injection on stderr. |
| Lifecycle | spice agent ensure / supervise |
Maintains one supervised, worktree-bound agent per worktree under a neutral skill prompt. |
| Steering | filesystem inbox + ACK <key>: ... |
Delivers durable operator steering and retires it only through semantic transcript acknowledgment. |
| Tasks | spice task ... |
Shares a phase-native Taskwarrior board across worktrees; task next owns allocation and git sync happens at task boundaries. |
| Sessions | spice session briefing |
Rehydrates current context from transcript forensics instead of chat memory. |
| Interface | spice serve |
Exposes lanes, live transcripts, steering, teams, task routing, and browser-visible diagnostics. |
| Conscience | spice maxim ... |
Judges assistant prose against repo maxims and routes violations back as steering. |
| Constitution | git pre-commit hook / spice study ... |
Enforces repo-shape, file-shape, complexity, magic-number, env-literal, and commit-message policy. |
Credibility signal
The strongest signal is not size or a test-to-source ratio. spice's own gate
demands assertion density, rejects assertion-free tests, runs integration paths
against real binaries such as Git and Taskwarrior, and treats module and symbol
reachability as zero-tolerance production wiring checks. The same self-passing
constitution that keeps this repository honest is what spice init installs
elsewhere.
A separate hardware stressor is kept deliberately narrow: spice has been battle-tested against real hardware workflows, including an agent-driven Meta Quest test rig. The public hardware demo waits until it can be reproduced with owned assets, public tooling, and no private user or platform data.
The constitution applies to itself. The repo's own largest production file sits under the project's 1,500-line flex ceiling, and the gate that prevents any file from silently growing past that ceiling is the same gate that guards every other repo spice is installed in. A constitution its own author exempts himself from is theater; this one isn't.
Honest feedback
One principle runs through the design: never let a thing fail silently, in either direction. When something succeeds, confirm it explicitly; when something fails, surface the failure rather than hiding it.
This shows up repeatedly:
- Unmatched ACKs as no-ops: When an agent ACKs a key that doesn't exist, the system reports "retired nothing" rather than silently dropping the attempt. The operator learns immediately that the agent misread or the key was stale.
- Curated conscience reinforcement: Properly curated maxims are near-universal operator preferences, not claims that can never be wrong. When one fires incorrectly (a false positive), the resulting steering should still reinforce good practice rather than derail the agent; that low cost of being wrong is what lets the conscience nudge aggressively. This depends on keeping the maxim set narrow, curated, and worth hearing even when imperfect.
- Resend under fresh key: If an agent ignores steering, resending the same item under a new key means it can't keep ignoring — the fresh key proves this instance wasn't handled, even if a similar one was.
- Explicit "this did nothing" feedback: Operations that complete without effect (like retiring a nonexistent inbox key) say so explicitly in the transcript, rather than succeeding silently and leaving the operator guessing.
The pattern is visible vs. silent, in both directions. A confirmation you can't miss is as valuable as an error you can't miss — both let you trust that silence means "nothing happened," not "something happened and nobody told you."
Session analysis is intentionally tiered. The current tier includes
spice session phases for contiguous working-phase spans and
spice session messages for message-level side/phase/flavor filtering.
Deeper report families that depend on richer topic/bucket modeling belong in
a separate analytics tier after the basic phase/message surfaces harden.
Why
You rarely know what you want until you watch it fail. Writing the spec up front doesn't change that — it commits the misunderstanding to a document you then have to maintain. And the channel you'd write it through, a human at a keyboard, has a bit rate that plateaued decades ago and is the slowest link in the loop.
spice takes the other route. The operator doesn't name the destination; they corral the agents toward it — watching what the agents emit and turning what they don't like into steering with the smallest possible gesture. The target is an evolving fixed point: the state the loop settles into when nothing it produces still provokes a correction. The spec is the output of that process, never its input.
Neither spec-driven nor observation-driven — both
Spec-driven development is waterfall for agents: it front-loads a written specification and assumes the implementer's speed is the bottleneck. The implementer's speed was never why waterfall failed — the discovery problem was. Cheap implementation doesn't remove discovery; it lets you generate precisely-wrong code at scale and maintain a precisely-wrong document beside it. All intent, no evidence.
Its mirror — observation-driven development, steering only by what the running system emits — fails the other way. With no target, you chase telemetry, fix whatever is in front of you, and never converge, because nothing is being converged toward. All evidence, no intent.
spice is the fusion. The transcript is one surface that is both: emitted behavior, and — the moment you quote-and-steer off it — declared intent. Observation supplies the truth and the gradient; the spec supplies the direction. The work lands at the fixed point where observed reality stops diverging from evolving intent. Intent kept honest by evidence; evidence kept on course by intent.
Is this for you
spice is opinionated on purpose, and the opinions are load-bearing: you can't drive a loop to a fixed point with minimal human input without encoding taste firmly enough for the machine to apply it for you. That makes spice a poor neutral tool and a sharp fit for a particular way of working.
It fits if you'd rather operate a fleet than hand-write code, you locate the craft in the structure rather than the keystrokes, you share its code posture — small bounded seams, ugly-fast cores allowed, no shims, fallbacks, or legacy — you trust listening over writing, and you run a supported agent driver (today: Codex or Claude Code).
It will fight you if your craft lives in the text, you want a tool that bends to your opinions instead of supplying its own, you're on an unsupported agent driver, or you need something stable and supported today. That isn't a defect; it is the cost of a narrow workflow with load-bearing opinions.
Install
uv tool install -e /path/to/spice-main
# or, for the released package:
uv tool install spice-harness
cd /path/to/your/repo
spice init # hooks, skill copy, state scaffolding
spice dev doctor # verify runtime, drivers, backends, and policy
The default install is a uv tool. Operators who deploy from a main tree should
use the editable form so the installed spice command resolves to that tree;
that editable main tree is the server deployment. Other worktrees remain
operated trees and do not supply their own runtime.
The common-dir layout is opt-in. Set uv's tool directories before installing if you deliberately want the tool environment and executable under a repository's shared git directory:
repo=/path/to/your/repo
common_dir=$(cd "$repo" && git rev-parse --path-format=absolute --git-common-dir)
UV_TOOL_DIR="$common_dir/spice/tools" \
UV_TOOL_BIN_DIR="$common_dir/spice/bin" \
uv tool install -e /path/to/spice-main
export PATH="$common_dir/spice/bin:$PATH"
spice init writes machine-local git hook shims under .spice/ (ignored via a
generated .spice/.gitignore), materializes the worktree skill copy, and prepares state
scaffolding. Repo-tracked policy lives in your pyproject.toml under
[tool.spice.*] tables. The command surface is always spice …. Entrypoint
resolution is installed-tool first: generated git hooks invoke ambient spice
directly, and spice dev doctor reports the active package source so a worker
checkout cannot silently become its own runtime.
Graceful degradation
spice is built to work without requiring its optional companions — RTK, the local judge, and TTS all degrade gracefully when absent or unavailable.
RTK (context compaction): When rtk is not installed or not on PATH, the agent wrapper skips telemetry rewrite and passes command output through uncompacted. The loop still works; context just grows faster from verbose tool output.
Local judge (conscience): The default judge binary is afm-cli (Apple Foundation Models CLI, macOS only). When unavailable, configure an alternative with spice config judge --bin /path/to/judge; the judge interface is a simple stdin/stdout contract. Without a working judge, the conscience is silent; maxim enforcement stops, but all other surfaces (steering, tasks, constitution) remain functional.
TTS (speech synthesis): Text-to-speech defaults to macOS say. When unavailable, speech commands and the serve UI's narration mode report the speech failure while leaving the transcript authoritative; audio is best-effort ear candy and never blocks message flow.
Non-Mac paths:
- Judge: Any local model supporting the conscience's prompt-response contract works. Ollama + a small instruct model, AWS Bedrock, or a custom binary that reads the prompt from stdin and writes the verdict to stdout.
- TTS: Linux alternatives like
piperorespeak-ngcan be wired through the external backend:spice config say --backend external --command "/path/to/tts-wrapper" --content-type audio/wav.
The design principle: everything gracefully degrades, nothing hard-requires macOS-specific tools in a way that breaks the loop.
Agent command wrapper
Agents run shell commands normally. In an agent-bound worktree, spice installs static zsh/bash startup hooks that transparently reexec the first command shell through:
spice agent run -- <shell> -c "<original command>"
That wrapper owns stderr before the command runs. It prints pending inbox
steering and keep-working guidance, connects to the supervisor side
channel, asks rtk rewrite for command telemetry routing when RTK is installed,
routes git through the worktree shadow environment, leaves spice on the
installed tool, routes bare python and python3 to the deployment
interpreter, and loads configured wrapper groups. Descendant shells keep the
static hook environment without a second reexec, so steering is delivered at
command boundaries without double-injecting nested shells.
Wrapper groups live in tracked config:
[tool.spice.agent]
wrappers = ["common", "repo-tools"]
[tool.spice.wrappers.common]
wrap = ["grep", "find", "git"]
[tool.spice.wrappers.repo-tools]
codegen = { argv = ["uv", "run", "python", "-m", "tools.codegen"] }
Use wrappers for agent-owned execution where command output is also an
operator steering surface. The full contract, including RTK rewrite routing and
mounted-command boundaries, is in
docs/cli/wrapper-commands.md.
Agent defaults
A project can set its default supervised-agent launch model and effort in
tracked config, either by editing pyproject.toml or by running
spice config agent --scope project --model ... --effort ...:
[tool.spice.agent]
model = "gpt-5.5"
effort = "xhigh"
An operator can override those defaults for just the current worktree:
spice config agent --scope worktree --model gpt-5.5 --effort xhigh
Resolution order is explicit launch flags, then worktree config, then tracked
project config, then the driver defaults. spice config agent keeps project
and worktree rows explicit-only, while the effective row includes driver
defaults so unconfigured repos still show what will launch.
Serve UI defaults
The serve UI opens each lane in Drive mode by default — agents auto-subscribe
to task projects they create or claim. This is a deliberate choice, not a hidden
constant. Set default_lifetime in [tool.spice.serve] to change it per repo:
[tool.spice.serve]
default_lifetime = "Steer" # "Steer" | "Drive" | "Drain"; default: "Drive"
- Steer — manual filter assignment only; no auto-subscribe. Use when you want operators to configure lanes explicitly before agents start pulling work.
- Drive — auto-subscribe to projects the team creates or claims. The right default for most repos: agents work their own work without needing the operator to configure lane filters first.
- Drain — boundary dissolved; lane sees all assignable work. Use for dedicated drain/review lanes that need full visibility.
Autonomy-on-startup should be a stated choice. A repo that wants conservative
defaults (operator configures before agents run) should set Steer. A repo
that trusts the allocator can leave Drive or switch to Drain.
Speech backend
Serve can read messages aloud through a configurable speech backend:
spice config say --voice Samantha --words-per-minute 190
The default backend is macOS say, which honors the configured voice and rate.
Linux or other non-Mac worktrees should configure an external backend command
instead:
spice config say --backend external \
--command "/path/to/tts-wrapper" \
--content-type audio/wav
The external command receives prepared UTF-8 text on stdin and must write
browser-playable audio bytes on stdout. Use a tiny wrapper around engines such
as piper or espeak-ng when their native flags, model paths, or output-file
behavior need adaptation. The content type should match the emitted audio.
Repo command mounts
A repo can also mount its own tooling into the spice namespace:
[tool.spice.commands]
release = ["uv", "run", "python", "-m", "spice.release"]
bench = ["python", "-m", "myproj.bench"]
spice release notes or spice bench --suite smoke then runs the mounted
command from the repo root with the remaining arguments passed through
verbatim. A mount may be a top-level verb or a dotted command path.
Top-level mounts that shadow built-ins still fail loudly; nested mounts under
built-ins are allowed.
Mounted path segments are ^[a-z][a-z0-9-]*$. A repo can mount one namespace
owner, or mount specific nested paths directly:
[tool.spice.commands]
toolbox = ["uv", "run", "toolbox"]
report.inspect = ["project-tool", "report", "inspect"]
spice toolbox lint css --fix then dispatches lint css --fix to toolbox.
spice report inspect --limit 40 dispatches the mounted nested path directly.
Library seam for repo tools
Mounted commands and tracked pre-commit extensions may import a deliberately
narrow Python seam from spice instead of vendoring harness scaffolding. This
surface is source-stable for target repos: public names in the modules listed
below are not removed or renamed silently, and incompatible changes require an
explicit contract update. Underscored names remain private.
-
spice.errors:SpiceErrorfor user-facing command failures. -
spice.policy: constitution constants andflex_limit. -
spice.flexstate: flex-limit sticky-state persistence and rename helpers. -
spice.locking: cross-platform advisory file locks. -
spice.paths: repo-root, state-dir, atomic write, and tool-resolution helpers. -
spice.procs: process-group spawn, liveness, and termination helpers — cross-platform POSIX and Windows support for spawning process groups, checking liveness, and clean termination. Public functions:popen_new_process_group_kwargs()— returns platform-appropriate kwargs forsubprocess.Popento spawn a new process groupterminate_process_group(process, *, signum=None, timeout_seconds=2.0)— gracefully terminates a process group with fallback to force-kill after timeoutterminate_process_group_id(pgid, *, signum=None)— terminates a process group by IDprocess_group_is_running(pgid)— checks if a process group is still aliveprocess_id_is_running(pid)— checks if a process ID is still running
Example usage:
import subprocess from spice.procs import popen_new_process_group_kwargs, terminate_process_group proc = subprocess.Popen( ["long-running-server"], **popen_new_process_group_kwargs(), ) # ... later ... terminate_process_group(proc, timeout_seconds=5.0)
-
spice.repocfg: tracked[tool.spice]table readers. -
spice.studies.walk: tracked/staged path walkers, repo policy exclusions, staged renames, and git blob reads. -
spice.studies.fileloc,spice.studies.complexity,spice.studies.magicnums, andspice.studies.envpolicy: finding dataclasses plusscan_*,detect_*, andrender_*_boardhelpers for project-specific studies. The flex+sticky scans (scan_staged_loc_violations,scan_staged_complexity_violations) are pure queries by default; only a committing gate passespersist=Trueto advance the sticky floor, and it must pair that with the matchingclear_file_loc_sticky_state/clear_complexity_sticky_stateon gate success. The scan ratchets the sticky set up (a flex breach holds the file to the base limit); the success-clear prunes it down (a file back under base is released). Run one half without the other and you get permanent ratcheting or no release at all.
Everything else is an internal implementation detail unless this section names it. A repo tool that needs an unlisted module should either vendor that helper or first add the helper to this seam with tests and a stability note.
Interface
spice serve is the operator interface for the loop. It can compose multiple
agents into a single Drive lane, split worktrees into parallel lanes, route by
task filter, show live transcript attachments, and expose the control surfaces
needed to steer or audit a running session.
The serve header and browser title default to [project].name from
pyproject.toml; set [tool.spice.serve] brand = "Name" to override them.
Binding spice serve to 0.0.0.0 or another wildcard address intentionally
degrades the WebSocket Origin guard: any Host on the bound port is compatible,
so the check becomes Origin-equals-Host rather than the rebinding-resistant
authority match used for loopback or explicit binds. Use --auth-token; on
wildcard binds the supplied token, not the Origin authority match, is the
operative defense.
| Compose and route | Parallel lanes |
|---|---|
| A composed Drive lane groups multiple worktree-bound agents behind one operator control surface. | Separate lanes keep concurrent work readable while preserving per-agent Drive and speak controls. |
| Lane controls | Steering and ACKs |
|---|---|
| Filters, metrics, info, and worktree assignment live in the lane header. | Operator steering, ACKs, labels, and transcript controls stay visible in the live stream. |
| Attachments in transcript | Live image evidence |
|---|---|
| Transcript attachments remain browsable inside the lane. | Screenshots, browser captures, and diagnostics stay part of the operating record. |
The constitution
The pre-commit gate is the executable form of the project's opinions — see spice/policy.py. Highlights:
- namespace packages only; no
__init__.pyunder declared package roots; - file names match
^_*[0-9a-z]+_*$; splitting a file requires naming the seam (no*2.py, no generic continuation shards); - files flex to 1500 lines but a breach holds them to 1000 until they shrink; routines flex the same way around CCN 20 / length 80;
- magic-number regressions are a ratchet against
HEAD, not an amnesty; - env-literal inventory covers
SPICE_*,CODEX_THREAD_ID, andCLAUDE_CODE_SESSION_IDby default; target repos can add tracked name regexes with[tool.spice.policy] env_name_patterns; the waiver may live on the literal line, as a standalone waiver comment directly above the statement, or anywhere inside the wrapped statement carrying that literal; - env-name ledger accounting compares
[tool.spice.policy] env_namesexact names with literal env names extracted from supported access forms; dynamic access sites still belong to the presence waiver gate because they have no exact name to ledger; - commit subjects fit in 100 columns; bodies are auto-folded.
The gate applies to spice itself: this repository is its own first target. Target repos can keep their own tracked gate lanes under the same hook by declaring mounted commands and pre-commit policy:
[tool.spice.commands]
fmt-cs = ["dotnet", "format"]
[tool.spice.policy]
pre_commit = [
{ label = "format C#", mount = "fmt-cs", formatter = true, when = ["*.cs"] },
{ label = "assets", run = ["python3", "-m", "tools.assets"], when = ["Assets/*"] },
]
pre_commit_success = [{ label = "clear asset sticky state", run = ["python3", "-m", "tools.assets", "--clear-sticky"] }]
[tool.spice.policy.pre_commit_builtins]
formatters = false
"magic-numbers" = { label = "project magic", run = ["python3", "-m", "tools.magic"] }
Built-in pre-commit keys are repo-shape, staging, repo-docs,
formatters, local-paths, serve-web-typecheck, python-typecheck,
env-policy, file-shape, complexity, magic-numbers, reachability,
symbol-reachability, assertion-free-tests, and private-internals. The
serve-web-typecheck key no-ops in repos without the serve static sources it
gates. They run before extension steps unless an individual built-in is
disabled or replaced in tracked policy. pre_commit_success uses the same
command shape as pre_commit, but runs only after the whole gate has passed,
alongside sticky state cleanup.
python-typecheck runs Pyright against the package roots resolved for the
target repo and points Pyright at that repo's Python environment. The resolver
uses a repo-local active VIRTUAL_ENV, then .venv, then the uv project
interpreter. Non-standard layouts can set
[tool.spice.policy] python_typecheck_interpreter = "path/to/python"; relative
paths resolve from the repo root.
Reachability is provider-backed across two granularities sharing one seam. The
built-in python provider gates whole modules that tests can import but
production roots cannot, and — at function/class/method granularity — symbols
inside production-reachable modules. [tool.spice.policy].reachability_providers
lets a repo wire C#, JavaScript, Lua, or other analyzers into the same boards: a
finding's kind routes it to gate:reachability (module) or
gate:symbol-reachability (any symbol kind), so both gates are polyglot and no
finding is gated twice. Reachability findings are zero-tolerance pre-commit
failures, so exhaust must be wired into production or deleted with its tests.
Mutation testing is available as an explicit study, not a default pre-commit cost:
spice study mutations --staged --test tests/test_messagepayload.py --max-mutants 12
spice study mutations spice/serve/payload/message.py \
--test tests/test_messagepayload.py \
--ratchet .spice/mutation-ratchet.json
The mutation study targets changed Python source files by default, or the files
passed explicitly. It runs a bounded AST-mutant sample per module, reports
per-module mutation scores, lists tests that killed no selected mutant, and can
compare scores against a JSON ratchet with --ratchet or refresh one with
--write-ratchet.
Extension steps run from the repo root and receive the staged paths,
newline-separated, in the SPICE_STAGED_PATHS environment variable. A step
with when globs runs only when a staged path matches (fnmatch against the
repo-relative path, * crosses directory separators) and receives just the
matching paths; a step without when always runs and receives every staged
path.
Set formatter = true on a command step that rewrites matching staged files;
after it exits successfully, the gate re-stages those same SPICE_STAGED_PATHS
so the formatted content lands in the commit.
Release
Releases are cut from a clean synchronized worktree with this repository's
mounted spice release command. Lane branches are allowed; the release command
pushes the prepared release commit to origin/main. Other repositories can
mount their own release command without competing with a spice built-in.
spice release prepare minor # bump, validate, commit, stop before publish
spice release notes > /tmp/spice-release-notes.md
spice release publish --notes-file /tmp/spice-release-notes.md
spice release minor # one-pass bump, validate, commit, publish
For curated GitHub release notes, generate the draft after prepare and edit
from that file instead of relying on session memory. The draft is built from
first-parent commits in the exact previous-release-tag-to-release-commit range,
grouped by landed task project metadata, rewritten into highlight-style bullets,
and records that range in the package notes.
When release history is unusual, pass --release-commit <rev> to choose the
commit used for spice release notes or spice release github. Use it for
tag repair, delayed publication, or a prepared version whose correct release
target is not the default resolver. spice release publish --release-commit
is intentionally stricter: the commit must resolve to HEAD, because publish
builds and uploads artifacts from the current worktree before creating the
GitHub release.
Use a minor release when users can do something new or observe changed
behavior: new commands or flags, new configuration, new spice serve or task
workflow behavior, additions to the public library seam, changed output or
artifacts, or any compatibility break while the project only has patch/minor
release lanes. If a release contains both patch-level fixes and minor-level
surface changes, choose minor.
Use a patch release only when the shipped contract is unchanged: bug fixes, documentation clarifications, packaging fixes, or internal test/build/tooling changes that do not give operators a new capability and do not alter CLI, configuration, UI, task/session semantics, or the public library seam.
Status
Work in progress: an extraction-in-progress toward a standalone, releasable product. Surfaces are still settling; the loop described above is real and exercised daily, and this repository is its own first target. spice was extracted from daily use driving a real project, not designed top-down — the source of both its coherence and its opinions.
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 spice_harness-0.14.0.tar.gz.
File metadata
- Download URL: spice_harness-0.14.0.tar.gz
- Upload date:
- Size: 742.2 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.11.23 {"installer":{"name":"uv","version":"0.11.23","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
a2013e29c133631b27ba836adf2450ca55e538601242e0e3eac0c5999abd4482
|
|
| MD5 |
75692aaf8fb76a1e5bd4d2a13d60d116
|
|
| BLAKE2b-256 |
4231bc498586712a67f700917103bae4563514e23480423d99bb521811e6f232
|
File details
Details for the file spice_harness-0.14.0-py3-none-any.whl.
File metadata
- Download URL: spice_harness-0.14.0-py3-none-any.whl
- Upload date:
- Size: 574.0 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.11.23 {"installer":{"name":"uv","version":"0.11.23","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
9490aed0fbab296dc1222b42876d0bc0357369aa4125e1dcf8345395c03fcb1e
|
|
| MD5 |
b451c328277c7eb3632b34409190f19e
|
|
| BLAKE2b-256 |
993d8d3fe7d3c5dfd22c43cd03f9ab3e1e63be328b0dcc379cd11c6b801d3227
|