Integration: SageOx (ox)¶
Status: Design-locked · Implementation: Phased; L1 + L2 in Vox v1, L3 in v1.1, L4 deferred.
SageOx (ox) is agentic context infrastructure
— a git-tracked ledger of team-context atoms ("murmurs") that AI coding agents
consume before they act. Vox plugs in as the local audio recording engine ox
doesn't ship: capture spoken intent from any source, transcribe locally
(BYOK or fully local), write murmurs into the ox ledger, and have them
auto-available to every team member's AI coworker via ox agent prime.
This document is the single source of truth for the Vox ↔ ox integration: architecture, contract mapping, performance constraints, and the open conversations we need to have with the upstream ox team.
What ox is, in one paragraph¶
ox (MIT, Go, github.com/sageox/ox, $15M
funded as of 2026) orchestrates adapters that read each AI tool's
session format (Claude Code, Codex, Gemini, Aider, OpenCode, Cursor,
Windsurf, Pi, Amp, Copilot, Cline). Adapters are separate binaries
implementing a versioned public protocol
(pkg/adapterprotocol, ProtocolVersion = 1). Team context is stored as
murmurs — small JSON files in
data/murmurs/YYYY-MM-DD/HH/<id>.json under the ledger directory, synced
via a git remote with GitHub backend support. The web app at sageox.ai
handles team management, dashboards, and currently audio recording +
transcription of team discussions. Local CLI users have no
locally-driven audio path today.
The gap Vox fills¶
ox's audio capture lives in the web app. Local CLI users cannot today:
- Record a Zoom / Meet / Teams call's system audio + their own mic
- Capture an in-person meeting via lapel / array mic
- Dictate into the ledger from the terminal
- Capture audio when offline
Vox is the local recording engine ox doesn't have. The intent envelope maps almost 1:1 onto ox's murmur format, making ox murmurs a near-native sink.
The four-layer integration model¶
Vox can integrate with ox at four layers, of increasing depth and effort. We ship the first two in Vox v1, the third in v1.1, defer the fourth.
| Layer | What it is | Effort | Phase |
|---|---|---|---|
| L1. Direct murmur file writer | Vox writes JSON files directly into data/murmurs/YYYY-MM-DD/HH/<id>.json inside the ox ledger directory. Zero-dependency on the ox CLI running |
Low | v1 |
L2. First-class ox-ledger sink in sink/v1 |
Configurable Vox sink type (templated topic / importance / scope, filterable, batches git commits) | Medium | v1 |
L3. cmd/ox-adapter-vox/ compliant adapter binary |
Implements pkg/adapterprotocol. Surfaces in ox status, ox doctor. Registered upstream |
Medium | v1.1 |
| L4. Bidirectional — Vox routes informed by recent ox murmurs | Vox's router reads recent ox murmurs to make better intent-classification decisions | High | Deferred |
L1 underlies L2 — L2 is the configuration and lifecycle layer; L1 is the file-write mechanic. L3 is the formal handshake with ox so Vox shows up as a first-class citizen. L4 closes the loop and is the future work.
Murmur format mapping¶
ox's MurmurFile schema (from internal/ledger/murmur.go):
type MurmurFile struct {
SchemaVersion string // "1"
ID string // UUIDv7
Timestamp time.Time
AgentID string
AgentType string // "claude-code", "vox", etc.
PrincipalID string // who the agent works for
PrincipalType string // "human" for now
Topic string
Importance string // "critical", "normal", "ambient"
Content string
Metadata map[string]string
Tags []string
Scope string // "ledger" or "team"
}
Maps from a Vox IntentEnvelope (from sink/v1):
| ox murmur field | Source in Vox envelope | Default rendering |
|---|---|---|
schema_version |
(constant) | "1" |
id |
EnvelopeID |
(UUID, already compatible with UUIDv7 conventions) |
timestamp |
StartedAt |
RFC3339 UTC |
agent_id |
sink config agent_id_template |
vox-{{ .InstanceID }} |
agent_type |
sink config agent_type (constant) |
"vox" |
principal_id |
Speaker.Label (when present) |
empty if unknown |
principal_type |
derived from Speaker.SourceKind |
self → "human"; online/in-person → "human"; file → "recording" |
topic |
sink config topic_template |
voice/{{ .Envelope.Speaker.SourceKind }}/{{ .Envelope.Intent.Kind }} |
importance |
sink config importance_template |
{{ if gt .Envelope.Intent.Confidence 0.8 }}normal{{ else }}ambient{{ end }} |
content |
Transcript |
UTF-8, no transformation |
metadata |
Custom keys namespaced vox.* + key envelope fields |
See below |
tags |
derived | [vox, source:<kind>, intent:<kind>] plus filtered tags from envelope |
scope |
sink config scope |
"team" |
metadata payload (mapping to murmur.Metadata, a map<string,string>)¶
| Key | Source | Notes |
|---|---|---|
vox.session_id |
SessionID |
Group voice envelopes by session |
vox.stream_id |
StreamID |
Per-stream identifier |
vox.parent_id |
ParentID |
For derived envelopes (LLM responses) |
vox.source_kind |
Speaker.SourceKind |
self/in-person/online/file |
vox.intent_kind |
Intent.Kind |
prompt/command/etc. |
vox.intent_confidence |
Intent.Confidence |
Stringified float |
vox.asr_backend |
Provenance.ASRBackend |
e.g., whisper-cpp |
vox.captured_at |
Provenance.CapturedAt |
Original audio time |
vox.pipeline_version |
Provenance.Pipeline |
e.g., vox/0.1.0 |
vox.audio_ref_location |
AudioRef.Location (if present) |
S3 URL or similar |
vox.duration_ms |
Duration |
In milliseconds |
User-supplied Custom["vox.*"] keys override / extend the defaults.
Performance — git commit batching is critical¶
The ledger directory is a git repository. Per-envelope git commit would
balloon repo size, slow ledger operations, and stress the GitHub sync path
ox uses for team distribution.
Required behavior of the ox-ledger sink:
- Write murmur files immediately. File I/O is cheap; per-envelope writes are fine.
- Batch git commits. Default flush interval 30 seconds, configurable
via
git_commit_interval. A single commit covers all murmur files written in that window. - Never push automatically. Push is the user's choice (or ox's daemon's choice, when it's running). The Vox sink writes + commits locally and stops there.
- Coordinate with ox's daemon when present. ox's
internal/daemon/likely handles ledger writes via IPC to prevent contention. When the ox daemon is running, Vox should defer to it via the adapter protocol (Layer 3) instead of writing files directly. Layer 1 (direct write) is the fallback when ox daemon is absent.
This pattern matches ledger.WriteMurmurRaw() (in
internal/ledger/murmur.go), which exists specifically so the daemon can
delegate file I/O via IPC. Vox's adapter (Layer 3) should call into this
path; Layer 1 standalone falls back to direct file writes when no daemon
is reachable.
Versioning compatibility¶
ox's pkg/adapterprotocol declares ProtocolVersion = 1. The contract:
- Vox's adapter binary MUST declare
protocol_version: 1in itsinforesponse. - If the local ox CLI has a higher minimum supported version than Vox's adapter declares, ox refuses the adapter at registration time.
- When
pkg/adapterprotocolbumps tov2, Vox publishes av2-capable adapter alongside (or replacing, depending on whether the breaking change matters to our usage). - The murmur schema (
SchemaVersion: "1") is independently versioned. Vox writesschema_version: "1"murmurs until ox publishes a"2".
Both versions are gates Vox checks at startup. Mismatch fails fast with a clear error pointing the user at the upgrade path.
Upstream conversations needed¶
Four items to surface with the sageox team before sinking implementation
effort. The full GitHub Discussion text is in
ox-github-discussion-draft.md.
1. Conflict with their roadmap¶
ox may already plan to ship local audio capture. A 5-minute conversation up front prevents working at cross-purposes. The likely outcomes:
- They have a local-audio plan and welcome contribution. Best case — we contribute the recording engine instead of building a parallel one.
- They have a local-audio plan and prefer to ship their own. Vox positions as a complement (broader capture sources, more sinks) rather than as the recording engine.
- They have no local-audio plan. Greenlight to ship Vox + integration as designed.
Action: open a GitHub Discussion on sageox/ox before writing the
adapter binary. Discussion draft prepared.
2. Trademark / branding¶
"ox" / "SageOx" are upstream's marks; "Vox" / "Blackrim Vox" are ours. The combination ("Vox is an ox adapter") is fine but worth being explicit in the README, docs, and any marketing:
Vox is a third-party adapter for SageOx. Not affiliated with SageOx Inc.
This phrasing belongs in:
- Vox's README "See also" section (already mentions Blackrim, will add ox)
- The Vox docs integration page (this file — see footer)
- The ox-adapter-vox binary's info response (in the Description field)
- Any blog post / launch announcement
3. Murmur write performance (technical coordination)¶
Documented above. Worth raising in the GitHub Discussion so:
- The upstream team can confirm or correct our understanding of the
daemon's role.
- We agree on a contention model (file locks? IPC delegation? both?).
- We agree on a reasonable default git_commit_interval.
4. Versioning compatibility (technical coordination)¶
Documented above. Worth confirming with upstream:
- Their cadence for protocol version bumps (we want stable v1 for at
least Vox's v1 lifetime).
- Their stance on backporting protocol fixes (if v2 breaks something for
v1 adapters, do v1 adapters get a fix window?).
- Whether new capability constants (audio_capturer, murmur_writer) are
welcome additions to pkg/adapterprotocol.
Capability constants — proposed additions¶
Vox needs two new capability constants in pkg/adapterprotocol. Both are
additive (non-breaking):
// Existing
const (
CapSessionReader = "session_reader"
CapHookInstaller = "hook_installer"
CapIncrementalReader = "incremental_reader"
CapFileWatcher = "file_watcher"
CapSessionImporter = "session_importer"
CapServeMode = "serve_mode"
CapSubagentController = "subagent_controller"
CapRulesInstaller = "rules_installer"
CapCommandsInstaller = "commands_installer"
CapCapturePrior = "capture_prior"
)
// Proposed additions
const (
CapAudioCapturer = "audio_capturer" // Adapter captures live audio (mic, system audio, etc.)
CapMurmurWriter = "murmur_writer" // Adapter writes murmurs directly into the ledger
)
These are tiny PRs to sageox/ox and pose no risk to existing adapters.
Submitted alongside the ox-adapter-vox registry entry.
Registration paths¶
Two options for where ox-adapter-vox lives in ox's registry:
Option A — In sageox/ox-adapters (the external adapter repo):
# Added to internal/adapter/registry.yaml in sageox/ox
- name: vox
display_name: Vox
description: Local audio capture + transcription → murmurs in the ledger
type: session
bundled: false
binary: ox-adapter-vox
repo: sageox/ox-adapters
capabilities: [audio_capturer, murmur_writer, hook_installer, serve_mode]
detect_commands: [vox]
Pros: standard path for non-bundled adapters; sageox curates. Cons: sageox-controlled release cadence; small lag for our updates.
Option B — In jsgerman-oss/blackrim-vox (Vox's own repo):
- name: vox
display_name: Vox
description: Local audio capture + transcription → murmurs in the ledger
type: session
bundled: false
binary: ox-adapter-vox
repo: jsgerman-oss/blackrim-vox
capabilities: [audio_capturer, murmur_writer, hook_installer, serve_mode]
detect_commands: [vox]
Pros: we own the release cadence; the adapter ships with the main Vox
binary; one source of truth.
Cons: sageox has to be comfortable trusting a third-party repo field.
Recommendation: Option B. Vox owns the adapter, sageox curates the registry. Confirms in the GitHub Discussion.
Implementation phases¶
v1 (initial Vox release)¶
- L1 (direct file writer): implemented inside the
ox-ledgersink. - L2 (
ox-ledgersink): full sink/v1 implementation with templating, filter block, git commit batching. - Detection:
ox-ledgersink auto-detects ledger dir from~/.sageox/config.yamlorOX_LEDGER_DIRenv var; falls back to user-configured path.
v1.1 (formal adapter handshake)¶
- L3 (
cmd/ox-adapter-vox/): compliant adapter binary implementing the full ox protocol. When present, Vox prefers daemon IPC over direct file writes. - Registry entry: PR landed in
sageox/oxagainstinternal/adapter/registry.yaml. - Capability constants: PR for
CapAudioCapturer+CapMurmurWriterinpkg/adapterprotocol.
v2+ (deferred)¶
- L4 (bidirectional): Vox's router subscribes to recent ox murmurs to improve intent classification.
- Session writer: in addition to per-envelope murmurs, write a session-level summary that ox's session viewer treats as a first-class voice session.
- Bidirectional sync: Vox's S3 archive becomes addressable from ox via
a
vox.audio_ref_locationresolver.
Configuration sketch (full)¶
The ox-ledger sink config in a Vox sinks: block:
sinks:
- name: team-ledger
type: ox-ledger
ledger_dir: ~/.sageox/ledger # auto-detected from ~/.sageox/config.yaml when blank
agent_id_template: "vox-{{ .InstanceID }}"
agent_type: vox
topic_template: "voice/{{ .Envelope.Speaker.SourceKind }}/{{ .Envelope.Intent.Kind }}"
importance_template: "{{ if gt .Envelope.Intent.Confidence 0.8 }}normal{{ else }}ambient{{ end }}"
scope: team # "team" | "ledger"
schema_version: "1"
git_commit_interval: 30s
git_auto_push: false
prefer_daemon_ipc: true # use ox daemon IPC when reachable; fall back to direct file write
filter:
intent_kinds: [prompt, command, todo, note, summary, llm_response]
source_kinds: [self, in-person, online]
min_confidence: 0.6
include_derived: true
Files in this integration¶
| Path | Purpose |
|---|---|
ox.md (this file) |
Integration design + upstream conversation tracking |
ox-github-discussion-draft.md |
Text to post on sageox/ox Discussions |
../extensions/sink-v1.md |
Sink contract; includes ox-ledger as a built-in sink |
../../cmd/ox-adapter-vox/ |
Compliant adapter binary (skeleton) |
../../internal/sinks/oxledger/ |
Implementation of the ox-ledger sink type (post-implementation) |
Posture¶
Vox is a third-party adapter for SageOx. Not affiliated with SageOx Inc. "SageOx", "ox", and the SageOx logo are trademarks of SageOx Inc. and used here under their permitted-reference policy.