Use History to keep musical ideas, hear alternatives and recover an earlier song or one part. History is the song's journal: every change you hear is recorded, by whoever made it. Design: History Journal (building on Takes Reliability). Versions, history and comparisons explains identity and publishing; Recording and takes covers input recording; Record a loop covers score-driven loop capture.
Three related things#
| Name in the workflow | What it keeps | Where to find it |
|---|---|---|
| Song history | Source, resolved imports, macro controls, captured samples and tables, and desktop plugin state when available | The History pane (HISTORY in the header, File ▸ Song History…, the command palette) and the history strip in Source and on Bench |
| Recorded audio | Each completed input-recording pass, with the installed source stamped in its WAV | Transport recording controls, the History pane's Recorded audio list, and Library samples |
| Loop capture | The named audio produced by record | Sample bank; desktop also saves completed loops as recorded audio; browser Save idea retains the current loop in its sound snapshot |
Every change you hear is recorded#
Each record is a version, shown as v{n} (its stored label t{n} · b{beat} stays the address hooks use). A version records who made it (you, Copilot, an agent by the name it reported, or a peer), why (the prompt, the agent's label or the command-bar sentence), what changed (its title and the parts it touches) and which surface made it:
| Surface | Via | Notes |
|---|---|---|
| Run (⌘↵, the Run chip) | run | |
| Rack case, Routes, cables, Rack library modules | rack | installs through Run |
| Patterns pane, Pads, linked notes | patterns | when the surface runs what it writes |
| Timeline regions, scenes, markers, structure, variations | timeline | titled with the edit ("region placed on bass") |
| Mixer commits and mixer undo | mixer | |
| Bench / Clip live auto-swap | bench | at most one version per 2 s of continuous auto-swaps: the first at once, the latest when the window closes |
| Command bar | command | the sentence is the intent and the title |
| An import tab's Run | import | recorded in the SONG's history (its import closure moved) |
| Open, or a parked tab's Run | open | the song's history starts where listening started; controls are the opened module's initial values; returning to a song whose editing version holds the same source mints nothing |
| Copilot apply (every mode, Instant Song, the Arrange agent's write) | copilot | protected first, minted at apply — before any Run |
| An outside agent's apply or accepted proposal | agent | the same; the author is the name the MCP client reported when it connected, else "agent"; its why (else its label) is the intent |
An outside agent's apply_edit, create_volta or part restore_version on a file no Studio has open | agent | written into the song's store on disk, protected first (below) |
| ★ Keep, Save idea | idea | kept |
| Knob or scene moves | ride | see below |
| Revert this change | revert | intent "revert v12 (Copilot · darker bass)" |
| Restore's and a foreign edit's protective copy | checkpoint | intent "before restore v3", "before Copilot apply" |
Capture-to-code, macro-strip write-back, prompt promotion and the host's launch hook keep their own vias. An unchanged install mints nothing; when it carries an author or intent the editing version lacks, that version is annotated in place — so Running a copilot's applied edit later keeps Copilot's name on it instead of adding a duplicate. A version whose via a newer build wrote reads as other. Live scrub release is a Run. Undo and Redo of an edit heard at once (Write a song as a timeline § In Studio) mint nothing: the version they return to sounds again, in the sound already loaded, without waiting for its archive.
Rides. When you turn a knob or launch a scene and the controls then hold still for 1.5 s, while the engine plays the editing version's source, a ride version records the new controls (its source is the editing version's; it touches the controls). An equal ride mints nothing; controls moved only by automation playback, without a gesture, mint nothing.
Titles. An explicit name, else the author's intent, else "First idea" for the very first version only, else what changed ("beta: 2 → 20", "+ hats", "gate split in two — gate-a, gate-b", "3 knobs"), else its scope ("source unchanged · controls changed"). Numbers read musically: three significant figures, the source's units (800 Hz, 2.5 kHz, -6 dB). An edit to comments or spacing alone is titled notes. When both versions were installed, the compiled description (tempo, patches, tracks, patterns, effects, macros, scenes, arrangement, mixer) leads; the binding-level source comparison is the fallback for un-run or invalid source.
Keep an idea#
- ★ Keep (the ★ KEEP chip beside HISTORY in the header, ⌥⌘S on macOS / Ctrl+Alt+S elsewhere, File ▸ Keep Idea; command id
history.keep) keeps what is sounding — the installed source, the live knob positions and the launched scene — even while your editor holds a different draft. If that equals an existing version, the version is pinned instead. A card under the chip names it inline: type and Enter to name it, Escape to keep the automatic title; when your editor differs it offers also keep the draft. - Or, in the History pane's draft line, type a name such as “warmer bass” and choose Save idea: that keeps the draft in the editor. Rename a version from its row's ⋯; the row's ★ releases or keeps it. Ideas made before this release (kept, titled checkpoints) read as ideas.
- Change the song and Run it; select an older version and choose A/B with editing, or right-click its tick on the strip. Compare starts from the version your draft started from (editing) — or from your draft when you compare the editing version itself; your draft is one click away. Compare with… then a second row (or tick) compares any two versions. Selection and comparison preserve your working source.
- Choose a passage and render A/B to hear the alternatives.
- Choose Open this version (or Open and Run), Revert this change, or Restore part ▾ and a part. Opening changes the editor; Run installs it.
Revert this change (in a version's detail and in the compare window opened from a tick) puts back only the parts that version changed, from its parent: a changed block returns to the parent's, an added one is removed, a removed one is re-added, and controls return to the parent's values. A part whose working block no longer equals the version's — edited since — is a conflict: it is left alone and named in the toast, which says how to put it back (the parent's Restore part ▾). The revert protects your working copy first, compile-checks, is one undo step and Runs the live song. The copilot receipt's Undo uses it once the buffer has moved on since the apply.
A restore first saves the displaced working copy, including incomplete or invalid source. A failed backup blocks the restore; an asynchronous browser backup must finish before the editor changes. If source or imports change while waiting, restore is cancelled. Undo returns to the protected source and its captured context; the occurrence marker follows Undo and Redo. Restoring local history is unavailable while participating in a live room.
Every host restores as one engine transaction — the module, captured sample/table banks and macro values (applied at that boundary); refusal or cancellation keeps the previous sound and bank, and the installed snapshot is published only on acknowledgement. Nonfinite captured values reject the restore; controls absent from the restored source are ignored. Only accepted browser restores update the offline context, which baking and export wait on (a failed sync is retried first).
The selected version's detail names its author and via, quotes its intent, and reads your draft started here on the editing version (the head: where your edits started, not that un-run edits are sounding) and sounding now on the version the engine plays. The strip marks editing with an underline, sounding with a dot (a ★ in the primary on a sounding idea) and the selection with a band. A host install made before any mint this session has no guessed sounding identity.
Foreign rewrites are protected first: before a copilot apply, an agent's apply or accepted proposal, a restore or a revert rewrites the buffer, a checkpoint version keeps the working copy if it differs from the editing version (when it does not, nothing is minted and that version keeps its own intent), and Undo of the rewrite returns to that checkpoint.
The History pane#
HISTORY in the header (and File ▸ Song History…, file.song-history) focuses the workspace's History pane where it has one — Arrange keeps it as a tab beside the Agent pane — and otherwise, Classic included, docks it as a column on the right with its own ×; what is on screen stays beside it (Workspace layouts). Top to bottom:
- The header row: the save status (SAVED, SAVING…, SESSION ONLY, NOT SAVED · RETRY; the reason, the version count and the archive's size on disk are on hover; compact older audio appears while part of the archive is still in the pre-v4 layout, its hover naming how much and the
volta-studio --compact-history --applythat converts it — desktop only: nothing converts the browser's older blobs, which keep reading), ★ KEEP (the same keep as ⌥⌘S), the filters All · ★ Ideas · Mine · Agents (Agents: Copilot and outside agents), PART ▾ (only the versions that touched one part) and one search over titles, intents, authors, part names andv{n}. - The status line: one reserved line — saving before a restore, Compare with… waiting for its other side, passes picked for a comp, a version being heard — else what the strip's gestures do; rows never move.
- The strip: the same strip as in Source (below).
- The draft line: whether your editor differs from the version it started from, a name field and Save idea.
- The journal, newest first: a header per session (
Today · 14:02–14:40); versions fold into moves — consecutive versions by the same author through the same surface, touching an overlapping part, each within ten minutes of the last — read as one row (bass · 7 changes · 14:02–14:09) that opens in place. Ideas never fold. Rides fold under the version they were ridden on (◎ 2 rides). Each row is the author's mark (● you, ↵ the command bar, ◆ Copilot, ◇ an outside agent, ◈ a peer; ◌ a checkpoint, ↺ a revert, ◎ a ride, ○ an open), the title andv{n}, the age, ▶ (hear), ★ (keep) and ⋯ (rename, copy source). Pre-journal archives fold by the parts their source changed. Clock times are local: the machine's time zone on the desktop, the page's in the browser, each version at its own offset (daylight saving included). - The detail, when you select a row: author, via, "run at bar N" and the time; the intent quoted; markers (sounding now, your draft started here); the change's scope and its lines; badges for the captured imports, controls, sounds, plugins and scene (values on hover) with warnings inline; and the verbs ▶ Hear · A/B with editing · Open this version · Open and Run · Revert this change · Restore part ▾ · Compare with…; then the passage it plays ("plays bars 9–12 · where bass sounds", adjust / auto). A/B with editing opens the comparison in place (the version your draft started from against this one; your draft when it is that version); Compare with… then a second row or tick opens the compare window on the two. Restore part ▾ lists the version's parts, each with its ⟲ (that part's versions across the song, the shared part popover); with a part filter on, a ⟲ beside PART ▾ opens the same.
- Recordings ride under the version they were played against (
▸ ● 2 takes; the era is the stamp's source identity, as in Recording and takes): each row reads its length, its bars and "played against v{n}", with ▶ (the recording alone), USE (a new track that plays it), COPY (sample "voice.t1") and, for a pass, a tick: tick passes of one batch and COMP WITH… above the journal joins them into a comp (the same verb as Track Home ▸ Recording). Recordings no version here was played against, and the song's loops with KEEP AS TAKE, list under the journal.
▶ Hear is the one Hear (below, § Hear alternatives): solo, from the playhead, preparing then hearing … Esc stops, or why it can't be heard; dragging along the strip shares its renders and ends a Hear in progress.
The strip heads the Source pane (live song), Bench and the pane. Each session takes room in proportion to how long it lasted; the gap between sessions collapses to a gutter carrying the next session's start time (‹ when older versions did not fit). Ticks are tinted by who made them — you (accent), the command bar (primary), Copilot (agent hue), an outside agent (agent hue toward the ink), a peer (secondary), checkpoints faint and short; ideas fly a ★; rides are dots under their version. Every tick is a button named v147 · Copilot · darker bass. Hover previews the version; click selects it and reveals it in the pane; a primary drag auditions; right-click compares. While the pane is on screen it carries the strip and Source does not. A parked song's tab shows its history as it stood when the song was last live, read-only (hover only); a song not made live this session shows none yet.
Find a remembered change#
Search, the filters and PART ▾ narrow the journal; moves open where a search lands inside them. Restore part ▾ lists the version's parts, the parts it changed first, and the parts your song has that it lacks (Remove … — absent in v{n}). Restoring a deleted binding adds it back. Both compile-check the resulting song and preserve current work first.
Part history. Every surface that shows a part opens the same popover listing that part's distinct versions across the whole archive — ideas first, then newest first — where a version is the part's text plus, for a macro, its captured value, so a knob you only turned and kept is listed ("controls only · amount 0.8"). Open it from a song outline row (right-click, or its ⟲), the Rack case header's ⟲, a Patterns pane row's ⟲, a mixer strip's right-click menu, an Arrange track header's right-click menu, or a Bench cell's ⟲. A ⟲ lights when the part differs from your last idea or from the first version of this session. Each row offers ▶ here (the version spliced into your song, heard with your song's sounds and the live knob values — a macro's own value for a macro), ▶ original (the whole version as it was, with its own captured sound), A/B (your song against the version spliced in), diff (its text against yours) and use here. Use here compiles the spliced song first, keeps your working copy in history, writes one Undo step and does not Run; a controls-only version sets its knob.
Bench's gutter ghosts compare each binding with the editing version (after Open this version they are empty), never with the newest record. The Bay's TAKE pickers offer every version, ideas first, newest first within each, as ★ title · v{n}.
Compare's headline says identical only when the two snapshot hashes are equal (source and captured context); otherwise it names the scope that moved ("source unchanged · controls changed"), with the line count beside it when the text differs. A draft is compared with the captured context of the version it started from.
Hear alternatives#
▶ on a version or a part version is one click: it plays solo over the song, crossfaded, from the playhead's beat; it reads preparing while the render runs, and a second click or Escape stops it. A version that cannot be heard says why — a record saved before captured sound existed says it has source only. Hear, scrubbing and A/B share one render per version and passage.
The passage is chosen, not typed. It is the Arrange/Timeline selection when there is one; else the first phrase (four bars, or the scene if shorter) where a track the change touches sounds — a changed patch reaches the tracks that play it, a changed macro the tracks its routes modulate, a pattern the tracks that name it; else the transport loop; else from the bar before the playhead, for four bars. It reads as a sentence ("plays bars 9–12 · where bass sounds"); adjust shows the bar fields, and auto returns to the chosen passage. Bar numbers start at bar 1, under the song's own meter (a 7/8 song counts 3.5-beat bars, and playback starts the playhead's distance past its bar's own beat). The exclusive end and the start select the same notated range in each version; each version uses its own tempo and arrangement. Renders include pre-roll from song start, so a later passage includes earlier processing and section motion. Limits: at most 128 bars, 60 seconds, and a horizon within the first four minutes.
Desktop and browser render in separate engines. Native track plugins are hosted when their captured states and plugin installations are available. The browser uses a dedicated Worker. Render progress and refusals are visible. Dragging along the strip auditions the hovered version; releasing stops the audition and keeps the working source unchanged. Neighbor renders and caches reduce delay.
A/B switches preserve elapsed playback position and loop their passage. Optional Match loudness attenuates the louder side using measured integrated loudness. Null playback and the collapsible Difference analysis use the original levels. A silent passage is reported as silence; try a section where the part enters. Missing samples or unsupported dependencies fail explicitly.
These are reproducible renders from the captured starting context, not snapshots of a running reverb tail, plugin oscillator phase or arbitrary external device. Live input, external MIDI and neural inference require printed audio for history preview. Bus/master plugins also require printing. A plugin that cannot save its state is flagged. Browser plugin snapshots require desktop playback. Comparing a different file without an available sound context asks you to make it live.
Agents read and write it#
An outside agent over MCP (Use Volta from your own AI agent (MCP) § Song history) lists the journal, reads and compares versions, keeps one as an idea and restores a version or one part; Volta's copilot reads it through its history tool and the dossier's digest, and reverts or restores into its draft for you to verify and apply (Create with Copilot). A song open in a Studio with agent control is read live and restored through the same protected restore as the History pane (it needs Let Agents Apply Edits; the restore is not run). Any other file is read from its store and written under the store's lock, the same one the Studio's history writer takes.
Agent versions on disk. When an agent changes a file that no Studio has open, the file's current content is kept first (a checkpoint, "before codex edit", unless the editing version already holds exactly that source), then the change is minted as the agent's version, both before the file is written — a store that cannot record them refuses the write. No engine ran, so such a version's context holds the source's resolved imports and its initial control values but no sounds and no plugin states, and carries the warning recorded by an agent on disk; sound context not captured. Its change is never described as a sound change. Hear renders it with no captured sounds, so a synth-only song previews faithfully and one that reads samples is refused with that reason and the samples it reads; restoring it keeps the sound banks already loaded (it never empties them), as a legacy record does. The Studio captures the song's sounds the next time it runs it. A whole-song restore on disk moves the editing version to the restored one rather than copying it. A Studio that has the song open without agent control finds the store changed on its next save and merges it: the versions it lacks (matched by snapshot hash and time) join its journal under its next numbers, with parents renumbered to match; its own numbers never change; a ★ made outside lands on its copy with its title; a toast names who added them; and the union is saved. Two Studio windows on one song merge the same way. Only a history.json that cannot be read is still refused (save under a new name to keep both).
What is stored#
A version-3 snapshot includes source, the resolved import closure, current macro values, resource hashes, optional plugin-state bytes, and capture warnings. Resources include lossless PCM with sample rates and stereo channels, multisample zones, sample tempos, and wavetables. Both shells keep only the banks the song reads (intel::history_sample_keys; wavetables are kept whole); recall overlays them on the loaded bank. Edited import buffers are captured; incomplete source falls back to the known dependency map with a warning.
Sound resources are stored per sample (layout v4, engine/src/history.rs):
- Sample blob — a 24-byte header (
VSMP, u16 version 1, u32 sample rate, u16 channels, u64 frames, 4 zero bytes; little-endian) then f32 little-endian planar PCM: every left frame, then every right frame. - Wavetable blob —
VWTB, u16 version 1, u16 zero, u32 frame size, u32 frame count, a u32 mip count per frame and a u32 length per mip, then every mip's f32 samples in frame/mip order. - Manifest — one bank state as JSON (
"v": 4): its samples and zone samples by blob hash (with each buffer's root), sample tempos, zone fields, wavetables by blob hash, and whether it is song-scoped (partial).
Every blob and manifest is named by the SHA-256 of its bytes, so the same audio is stored once however many bank states, versions or Save As copies name it, and a new sample writes one blob and a manifest of a few KB. Recall reads the manifest and checks each blob against its name before it is decoded; a missing or altered sample refuses the recall instead of playing silence. Archives written before v4 hold one JSON blob per bank state; they keep reading. volta-studio --compact-history reports what it would do and the projected size; --apply (refused while a Studio window is open) converts those blobs to v4 — deleting each only after its manifest was written, re-read and found bit-identical — and deletes resources no version reaches that are over ten minutes old. Measured on the owner's archives: History Storage 2026 11 01.
The document stores occurrence numbers, parent occurrences, the working head, next sequence number, titles, keep pins, and each version's author, intent and touched parts (written only when present, so older archives read unchanged and re-save byte-identical). A content hash identifies a captured sound context; an occurrence number identifies its place in this song's history. Titles, pins, authors, intents and touches do not change content identity. The context also records the manually launched scene; it is hash-significant, but an absent scene is not serialized, so contexts captured before it hash as before. Authors are attribution, not authentication: an agent names itself. All captured snapshots are retained; there is no automatic 64/256-entry pruning or expiration.
- Desktop:
history.json,recordings.jsonandresources/—samples/<sha256>,tables/<sha256>,<sha256>.jsonmanifests (and any pre-v4<sha256>blobs) — in<workspace>/.studio-takes/<song path>/, or~/.volta/studio-takes/<path hash>/for external songs. Writes use an atomic replacement, filesystem synchronization, and a competing-writer check, and they run on a single history writer thread in submission order — a save answers Saving at once and Saved on the receipt; a finished recorded take's WAV and itsrecordings.jsonrow land the same way. A snapshot taken before its sound-resource archive exists carries a session-unique 64-hex key instead of the content hash;resources/index.jsonmaps it to the manifest once the archive worker has written it (writing only the blobs not already on disk), and history previews wait for that rather than fail. So the same sound can carry two keys within one session (the first Run's provisional key, later Runs' manifest name) and one per session: two versions' sound is compared by content identity (EngineBridge::history_resource_identity, applied to a whole context bybridge::resolved_take_context), never by raw key. The store's size on disk (and its pre-v4 part) is measured off the paint thread after each archive (EngineBridge::history_archive_size). Restoring a snapshot reads its archive on a background thread; the install that recalls it waits for the read off the paint thread. - Browser: IndexedDB
volta-song-historyholds documents and resources: sample and wavetable blobs asArrayBuffers under their hash and manifests under<hash>.json, shared by every song on the origin. A Run captures the song-scoped bank and ships only blobs the database lacks; they become durable with the history save that names them. The song's small localStorage pointer carries the archive through managed rename, move and trash. Save acknowledgement follows the database transaction and pointer write, and is correlated to the requesting song and revision. - Legacy history: old files and localStorage records migrate without deleting originals. Source-only records are labelled as such; their historical sound cannot be auditioned faithfully. Restoring them uses the current resources.
- Save As: copies the archive and resources (a parked tab's too); a File → New scratch song moves — history and pinned prints go with it, and the scratch file, recovery copy and old archive are removed. In the browser the scratch document goes after its pins are re-keyed (kept if they cannot be), and every Save As carries the song's dropped samples to the new document (
saveSourceAs/saveSongAs,runtime/public/studio-host.js). Managed rename/move carries history; external moves and cross-device synchronization remain manual.
Run never waits for the background resource archive.
Read the storage status: Saved on this device, Saving history…, Session only in this host, or History not saved: with the failure (a visible row can still be unsaved); Retry save retries. Corrupt histories and conflicting writers are preserved; Save As under a new name can preserve a competing in-memory history. Browser storage remains local to this origin and can be removed by clearing site data.
Recorded audio and loop lifetime#
Desktop recording controls expose a name, 1–64 passes, overdub, and punch points. Each batch gets the next name a person would type: voice.t1, voice.t2, …, then voice2.t1 for the next batch of the same name (named after the track you recorded for, else the input device, else take, unless you typed one); saved loops are keys.l1, kept loops keys.k1. A name is never reused, even after its WAV is deleted, and never shadows a bank sample; the engine also reserves collision-free names. A WAV is created exclusively, so a second batch cannot overwrite audio used by an existing comp. The capture keeps its own overdub mode even if another batch is armed before the completion is drained. Recordings named before this scheme keep their names and keep loading.
WAVs live at <song directory>/takes/<name>.wav, in Float32 at their actual sample rate. Their vlta stamp holds the source and imports installed when recording began. The recording is associated with that song even if the editor or active song changes before completion. The History pane lists each under the version it was played against and can copy the exact sample "name" reference. Write failures are visible; the completed PCM remains in the session sample bank.
Each recorded pass remembers where it was played (its punch window on the song clock): the Timeline draws it there, and Comp with… in Track → Recording turns ticked passes of one batch into a comp sized to that window (Recording and takes). The comp lane hatches a region recorded against a different version of the song than the one sounding, and a comp mixing versions is reported once.
Completed desktop loops keep the loop-pedal name in the live bank and also get unique saved-audio aliases (keys.l1, …). Keep as take saves a loop's current buffer as keys.k1, an ordinary take from then on. A browser track-bus loop is archived the moment it completes: its sample blob and the current bank state with the loop added are written at once, and the loop is indexed in the song's history pointer (recordings), so the next open puts the latest take of each loop name back in the bank — no Save idea needed. A loop finished in a song that has no saved path is archived but not indexed. Browser punch-pass tracking and looper microphone routing remain unsupported; granular input and Keep use the separate Granular synthesis workflow. No volta take CLI or executable history-reference syntax is introduced here.