# SoundForge Agent Guide
This guide describes the public SoundForge 0.2.2 API and its implemented
Wikimedia Commons behavior. SoundForge is a blocking Rust library. It currently
has one provider, `SoundProvider::WikimediaCommons`, and uses the official
Wikimedia Action API rather than scraping file pages or mirroring the catalog.
The same text is available at runtime as `soundforge::AGENT_GUIDE`.
## Client setup
Create a client with a descriptive User-Agent that identifies the calling tool
and provides contact information. An empty User-Agent is rejected. The default
discovery limit is 20; `with_discovery_limit` clamps its argument to 1 through
50.
```rust
use soundforge::{SoundForge, SoundKind, parse_sound_target};
let forge = SoundForge::with_user_agent(
"my-audio-agent/1.0 (https://example.com/contact)",
)?
.with_discovery_limit(12);
let target = parse_sound_target("search:laser")?;
let sounds = forge.discover(&target, SoundKind::GameAudio)?;
# Ok::<(), soundforge::SoundForgeError>(())
```
The client has a 90-second request timeout and disables HTTP redirects. Do not
construct altered provider URLs or download URLs yourself; discovery returns
the validated original URL in `SoundSummary::file`.
## Queries and kinds
`discover(&SoundTarget, SoundKind)` accepts these targets:
| `laser` or `search:laser` | `SoundTarget::Search` | Free-text audio search |
| `category:Sound effects` | `SoundTarget::Category` | Exact Commons category name, without `Category:` |
| `file:Laser (Gravity Sound).mp3` | `SoundTarget::File` | Exact Commons file title; `File:` is optional in the value |
| `https://commons.wikimedia.org/wiki/File:Laser_%28Gravity_Sound%29.mp3` | `SoundTarget::File` | Exact file from a canonical HTTPS Commons file-page URL |
| `top`, `popular`, or `trending` | `SoundTarget::Top` | Widely linked audio candidates |
| `latest`, `newest`, or `new` | `SoundTarget::Latest` | Recently created audio candidates |
Only an HTTPS `commons.wikimedia.org/wiki/File:...` URL with no credentials or
nonstandard port is accepted as a URL target. Empty targets, other hosts,
non-file Commons pages, and other Commons URL shapes return `InvalidTarget`.
`SoundTarget::is_collection()` is false only for `File`.
The kind is an intended-use ranking signal, not a provenance or suitability
guarantee:
- `SoundKind::Music` boosts music, song, instrumental, musical-performance,
orchestra, and symphony signals.
- `SoundKind::GameAudio` boosts sound-effect, video-game, game-sound, ambience,
ambient-sound, UI-sound, and Gravity Sound signals. It demotes science,
speech, pronunciation, audiobook, lecture, spoken-word, news, radio,
interview, and podcast signals, and separately demotes audio longer than two
minutes.
- `SoundKind::Any` applies no kind-specific score.
For `Top`, the provider query uses Commons category `Music` for `Music`, `Sound
effects` for `GameAudio`, and all audio for `Any`. `Latest` always queries all
audio. Search and explicit category queries do not change their provider query
according to kind; kind affects local ranking.
### Candidate and ranking behavior
Free-text terms are individually quoted before they reach Commons, so text such
as `incategory:Music` or `-speech` is treated literally rather than as search
syntax. SoundForge asks for up to three times the requested result limit,
capped at 50, then filters and ranks locally. Every normalized query term must
occur as a whole token in the title, categories, or description. Ranking favors
an exact title, then a title phrase, all title terms, title/category coverage,
some title coverage, and finally description/category-only coverage. The kind
score is added, and cross-wiki usage count breaks equal scores.
Category and top candidates are sorted by kind score and then cross-wiki usage.
Latest preserves the Action API generator index, whose query is requested in
newest-first creation order. Exact file lookup follows Commons title redirects
and returns the canonical title and page ID. A missing exact file, a non-audio
file, an unsupported MIME type, or a file rejected by the license filter is
reported as `NotFound`.
Provider search order and candidate bounds matter: SoundForge does not inspect
the entire Commons catalog, and filtering unacceptable candidates can produce
fewer than the requested limit. `usage_count` is a popularity signal, not a
quality or rights signal. `usage_count_complete` is true only when bounded
global-usage continuation completed; do not present a false value as an exact
total. Metadata continuation is limited to ten API requests.
## License evidence and preflight
Discovery admits only these normalized license families:
- `CC0-1.0`
- `Public-Domain` for generic provider-designated public-domain metadata
- `PDM-1.0` only when Commons explicitly identifies Public Domain Mark 1.0
- `CC-BY-2.0`, `CC-BY-2.5`, `CC-BY-3.0`, and `CC-BY-4.0`
- `CC-BY-SA-2.0`, `CC-BY-SA-2.5`, `CC-BY-SA-3.0`, and `CC-BY-SA-4.0`
Unknown licenses, noncommercial and no-derivatives licenses, legacy sampling
licenses, unsupported versions, and inconsistent license labels/URLs are
filtered out. For recognized Creative Commons licenses, a missing URL is filled
with the corresponding canonical URL. A supplied URL must use the expected
Creative Commons host, family, version, and path with no query or fragment;
matching HTTP URLs are canonicalized to HTTPS. Generic public-domain metadata
may have no URL, a valid HTTPS URL, or the matching Creative Commons Public
Domain Mark URL (which is canonicalized to HTTPS).
`SoundRights` retains the normalized license and URL, provider's plain-text
license label and attribution-required value, artist, credit, optional HTTPS
credit URL, usage terms, selected attribution line, metadata retrieval UNIX
timestamp, and Commons reuse-guidance URL. HTML metadata is converted to plain
text. Attribution is considered required for BY/BY-SA or when Commons says
`true`, `yes`, or `1`. Such a candidate is rejected unless it has usable artist
or credit text. When available, credit is the selected `attribution`; otherwise
SoundForge uses `<artist> via Wikimedia Commons`. The public-domain fallback is
`Wikimedia Commons public-domain source`.
Treat these fields as retained evidence, not a legal conclusion. Before use,
review `source_url`, `rights.license`, `rights.license_url`, `rights.artist`,
`rights.credit`, `rights.credit_url`, `rights.usage_terms`, and
`rights.provider_terms_url`. Preserve the title and source URL alongside the
attribution. Check the source page for trademark, privacy, publicity, cultural,
personality-right, and other restrictions that copyright metadata does not
resolve. For ShareAlike material, determine whether and how the obligation
applies to the intended work.
```rust
use soundforge::{SoundForge, SoundKind, SoundTarget};
let forge = SoundForge::with_user_agent(
"rights-preflight/1.0 (rights@example.com)",
)?;
let sounds = forge.discover(
&SoundTarget::File("Laser (Gravity Sound).mp3".into()),
SoundKind::GameAudio,
)?;
for sound in &sounds {
println!("Title: {}", sound.title);
println!("Source: {}", sound.source_url);
println!("Credit: {}", sound.rights.attribution);
println!("License: {} {}", sound.rights.license, sound.rights.license_url);
println!("Terms: {}", sound.rights.provider_terms_url);
}
# Ok::<(), soundforge::SoundForgeError>(())
```
Archive has another preflight: immediately before each download, SoundForge
looks up the canonical file again by title, reruns the license and metadata
checks, and requires the page ID to match the discovered `SoundSummary`. It
archives this fresh authoritative summary rather than trusting caller-mutated or
stale discovery metadata.
## Archiving and integrity
`ArchiveOptions::default()` writes to `audio`, does not skip existing archives,
and limits each file to 512 MiB. Set `max_download_bytes` to another byte limit;
zero disables that configured cap. Commons' exact advertised size remains an
integrity boundary even when the configured cap is disabled.
Each sound is stored under `<output>/<Commons page ID>/` as `audio.<extension>`
and `soundforge-audio.json`. The manifest contains format version `1`, the fresh
`SoundSummary`, relative audio path, exact byte count, local BLAKE3 digest, and a
complete marker.
For each download SoundForge:
- accepts only an original HTTPS `upload.wikimedia.org` URL with no credentials
or nonstandard port;
- rejects an unsupported MIME type before transfer;
- rejects a provided HTTP `Content-Length` that differs from Commons metadata;
- streams no more than the configured cap and the exact Commons size;
- requires the final byte count and Commons SHA-1 to match;
- checks file magic against the declared MIME type;
- computes a local BLAKE3 digest, flushes and syncs the file, writes the
manifest, and verifies the staged archive before installation.
The provider SHA-1 proves agreement with current Commons metadata. The BLAKE3
digest records local archive integrity. On later verification, SoundForge reads
at most the expected bytes plus one and requires byte count, SHA-1, and BLAKE3
all to match.
Downloads and manifests are built in a staging directory. Replacement first
moves a recognized destination to a backup, installs staging, attempts rollback
if installation fails, and removes the backup after success. Transaction,
rollback, staging-cleanup, and backup-cleanup failures are reported rather than
silently ignored. Numeric page IDs, safe relative paths, capability-based
directory access, regular-file checks, and symlink rejection protect archive
ownership and paths.
### Skip and repair behavior
With `skip_existing: true`, a complete existing archive is skipped only when its
current nonvolatile metadata matches, its manifest validates, and its audio
passes byte-count, Commons SHA-1, and local BLAKE3 verification. Retrieval time,
usage count, and usage-count completeness are ignored for this metadata match.
If the existing manifest still safely identifies a SoundForge archive for that
page ID but metadata or file verification fails, SoundForge downloads and
transactionally replaces it. This is the repair path. A malformed, unsafe,
symlinked, foreign, incomplete, or otherwise unrecognized manifest/output is
refused as `UnrecognizedExistingOutput`; `skip_existing` does not authorize
overwriting arbitrary directories. Without `skip_existing`, an existing
destination must still contain a fully valid matching SoundForge manifest before
replacement is allowed.
`archive` attempts every selected sound. Per-file failures are accumulated in
`ArchiveSummary::failed`; they do not make `archive` itself return `Err`.
`ArchiveSummary::is_success()` means that no selected sound failed. Top-level
setup failures, such as an invalid output path, still return `Err`. Inspect
`selected`, `archived`, `skipped`, `bytes_written`, `sounds`, and `failed`.
```rust
use std::path::PathBuf;
use soundforge::{ArchiveOptions, ArchiveProgressPhase, SoundForge, SoundKind, SoundTarget};
let forge = SoundForge::with_user_agent(
"archive-agent/1.0 (archive@example.com)",
)?.with_discovery_limit(5);
let sounds = forge.discover(
&SoundTarget::Search("Mozart symphony".into()),
SoundKind::Music,
)?;
let options = ArchiveOptions {
output: PathBuf::from("audio"),
skip_existing: true,
max_download_bytes: 64 * 1024 * 1024,
};
if let Some(title) = event.active_sound.as_deref() {
eprintln!("{title}: {} bytes", event.active_bytes_written);
}
}
})?;
for failure in &summary.failed {
eprintln!("{}: {}", failure.sound_id, failure.message);
}
assert_eq!(summary.selected, summary.archived + summary.skipped + summary.failed.len());
# Ok::<(), soundforge::SoundForgeError>(())
```
`archive_with_progress` emits `Starting`, `Downloading`, and `Completed`
snapshots. Active download events are emitted about every MiB and once at the
final byte count; a non-active `Downloading` snapshot follows every attempted
sound. The callback is synchronous and `FnMut`, so keep it fast and do not panic.
During an active transfer, `bytes_written` is the current call's successfully
archived bytes plus active bytes. `active_total_bytes` is the exact Commons size.
## Network, errors, and format safety
Action API requests are restricted to
`https://commons.wikimedia.org/w/api.php`. Source pages must be HTTPS on
`commons.wikimedia.org`; downloads must be HTTPS on `upload.wikimedia.org`.
Credentials, non-HTTPS schemes, unexpected hosts, unexpected API paths, and
nonstandard ports are rejected. Redirects are disabled, so redirects cannot
silently cross these trust boundaries.
Every API query sends `maxlag=5`. HTTP 429, HTTP 5xx, and JSON `maxlag` errors
are retried for at most three total attempts. Delay uses a numeric `Retry-After`
header, provider lag, or one-second then two-second backoff, capped by a
five-second total wait budget. HTTP-date `Retry-After` values are not
interpreted. Downloads are not automatically retried.
API responses are capped at 16 MiB, provider error bodies at 8 KiB, and archive
manifests at 2 MiB. `ProviderApiError` retains Action API error code and info.
`ProviderApi` reports final non-success HTTP status and a bounded body.
`Request` reports transport failures, `Json` reports malformed JSON,
`ResponseLimitExceeded` reports bounded-response violations, and
`VerificationFailed` reports metadata or integrity failures. Match the public
`SoundForgeError` variants when behavior must differ; otherwise preserve the
full displayed diagnostic.
The accepted MIME types and required signatures are:
| `audio/mpeg` | `mp3` | Two coherent MPEG frame headers, after an optional bounded ID3 tag |
| `audio/ogg`, `application/ogg` | `ogg` | `OggS` |
| `audio/flac`, `audio/x-flac` | `flac` | `fLaC` |
| `audio/wav`, `audio/x-wav`, `audio/wave` | `wav` | `RIFF` and `WAVE` |
| `audio/webm` | `webm` | EBML header `1a 45 df a3` |
| `audio/mp4`, `audio/x-m4a` | `m4a` | `ftyp` at bytes 4 through 7 |
Magic inspection retains at most the first 256 KiB. All other MIME types,
including `audio/aac`, are rejected. A file extension or provider MIME label by
itself is never enough to pass archival verification.