Skip to content

Commit 4054de4

Browse files
emeisazamclaude
andcommitted
Release oída 0.2.0: the listening server — unified gateway, MCP, host perception
Oída becomes the stack's main application: one process owning the MOSS engines and exposing the gateway contract (oida/gateway/v0.2), the host-perception path (oida/host-perception/v0.1) that routes, types, and audits other models' hearings, the official FastMCP server (10 tools, 4 resources, 3 prompts; stdio + streamable HTTP at /mcp), the embedded Akousmata library at /library/, lifecycle supervision (start/stop/status/ doctor/agent/gateway), and integrations for Hermes, Claude Code, Codex, and Tailscale-served remote access. Polish: /api index now lists the gateway and akousmata surfaces; gateway manifest version single-sourced from oida.__version__; claim-mapper docstring placed correctly; legacy JSON-RPC MCP shim marked deprecated; README germ-URL default corrected; CHANGELOG dated. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
1 parent c5565a1 commit 4054de4

44 files changed

Lines changed: 3122 additions & 277 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

CHANGELOG.md

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,23 @@
11
# Changelog
22

3-
## 0.2.0 - Unreleased
3+
## 0.2.0 - 2026-07-10
4+
5+
- **Oída is now the complete listening distribution and gateway**: installing
6+
it resolves AKOÚŌ (`akouo-contract`), Earworm's `akousma`, and the Akousmata
7+
navigator. One FastAPI process exposes the agent/dashboard, REST gateway,
8+
official streamable HTTP MCP at `/mcp`, and full library at `/library/`.
9+
- **Provider-neutral host perception**: `oida/gateway/v0.2` accepts either
10+
Oída-owned audio (`/gateway/listen`) or a declared report from an
11+
audio-capable host (`/gateway/harness`). Host-model observations cannot be
12+
silently promoted to DSP measurements; apparatus limits and unknowns remain
13+
explicit, while MOSS keeps its 16 kHz mono restrictions.
14+
- **Gateway lifecycle and local adapters**: `start`, `stop`, `status`, `doctor`,
15+
`agent`, `gateway`, and `integrate` commands manage a singleton daemon and
16+
install bundled Hermes, Codex, Claude, and Tailscale-remote integrations.
17+
MCP processes ensure or reuse the gateway and pin the active Python runtime.
18+
- **Earworm on every pass, durable memory only by consent**: session-scoped
19+
Earworm context is emitted for all gateway listens and host harness passes;
20+
Akousmata writes still require an explicit remember action.
421

522
- **Akousmata history embedded in the dashboard**: a new left-side
623
"Akousmata" section browses the shared store natively inside oída (search,

README.md

Lines changed: 63 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
11
# oída
22

3-
`oida` is a local listening agent for machine ears. It listens to audio files,
4-
the microphone, and the computer's own output, routes sound through MOSS-Audio
5-
and AKOÚŌ listening paths, extracts measured signal features, and normalizes
6-
everything into listening events that can be remembered, questioned, handed to
7-
germ as akousmata, or explored in the Sonic Field wiki.
3+
`oida` is the unified local agentic listening stack: the AKOÚŌ listening
4+
harness, Earworm provenance and memory protocol, and Akousmata listening
5+
library behind one agent, CLI, gateway, and install. It can listen through its
6+
own optional local engine (including MOSS-Audio plus deterministic DSP), or it
7+
can harness the audio perception already produced by Hermes, Codex, Claude, or
8+
another audio-input-capable host. Both paths produce the same accountable
9+
AKOÚŌ claims, Earworm session context, and optional durable Akousmata memory.
810

911
This project was previously named **AEAR**, then **hmm**; it is now **oída**.
1012
The Python package and primary CLI are `oida`; `hmm` and `aear` remain as
@@ -14,6 +16,22 @@ name **oída**.
1416

1517
## What Is Implemented
1618

19+
- **Unified gateway contract** (`oida/gateway/v0.2`) with two honest perception
20+
paths: Oída-owned audio through `POST /gateway/listen`, and host-owned model
21+
perception through `POST /gateway/harness`. `GET /gateway` advertises the
22+
installed AKOÚŌ, Earworm, and Akousmata contracts; `GET
23+
/gateway/schema/host-perception` publishes the host envelope.
24+
- **One lifecycle**: `oida start` ensures a singleton background gateway,
25+
`oida agent` starts it and opens the listening agent, and every stdio MCP
26+
adapter can ensure/reuse that gateway itself. The same process serves the
27+
dashboard, REST API, streamable HTTP MCP at `/mcp`, and the complete
28+
Akousmata navigator at `/library/`.
29+
- **Local host integrations** installed by `oida integrate`: a native Hermes
30+
plugin, Codex and Claude plugins, and a mobile-responsive private Tailscale
31+
surface. Their generated MCP configs are pinned to the active Oída runtime,
32+
so they do not depend on shell `PATH` or require a second app. Host adapters
33+
start the gateway without prewarming MOSS; the host-perception path stays
34+
lightweight until Oída-owned listening actually needs the local model.
1735
- FastAPI daemon (default `127.0.0.1:8765`) with task endpoints
1836
(`/transcribe`, `/events`, `/caption`, `/speech`, `/music`, `/qa`, `/think`,
1937
`/report`), the listening-event pipeline (`/listen-event`,
@@ -45,7 +63,7 @@ name **oída**.
4563
- **germ handoff** (shared akousmata store): after a listen, three actions —
4664
*Sound*, *Prompt*, *Lineage* — persist the listen as an **akousma** in the
4765
shared store (`~/Documents/SFL/akousmata`, via earworm's `py-akousma`) and
48-
deep-link germ (`OIDA_GERM_URL`, default `http://127.0.0.1:5178/import`).
66+
deep-link germ's `/import` route (`OIDA_GERM_URL`, default `http://127.0.0.1:5178`).
4967
Opt-in song identification (`OIDA_SONGID=1`, ShazamIO) enriches the record's
5068
`extensions.songid`.
5169
- **Sonic Field bridge**: "Explore in the wiki" searches the wiki, topics,
@@ -68,27 +86,45 @@ name **oída**.
6886
controls float just outside the box and appear on hover. Global hotkeys
6987
default to ⌃⌥L (listen) and ⌃⌥H (show/hide it).
7088
- CLI (`oida listen/live/background/memory/chat/sweep/corpus-qa/bench`), `ear`
71-
and `akoe` helper CLIs, and an MCP server exposing `oida_*` tools (legacy
72-
`hmm_*`/`aear_*`/`ear_*` aliases kept).
73-
- 113 unit tests that run without model weights.
89+
and `akoe` helper CLIs, and an official MCP server exposing compact
90+
`oida_*` listening, harness, memory, and live tools (legacy aliases kept on
91+
the HTTP compatibility surface).
92+
- A dependency-light test suite that runs without model weights.
7493

7594
## Quick Start
7695

77-
Prerequisites: Python 3.12+, `uv`, `ffmpeg` for non-WAV uploads or browser
78-
recordings, and a sibling checkout of `earworm` (the `akousma` dependency is an
79-
editable path source at `../earworm/packages/py-akousma`).
96+
Prerequisites: Python 3.12+, `uv`, and `ffmpeg` for non-WAV uploads or browser
97+
recordings. From this source workspace, one sync installs Oída together with
98+
the canonical AKOÚŌ, Earworm/akousma, and Akousmata packages:
8099

81100
```bash
82-
uv sync --extra dev
101+
uv sync --extra dev --extra moss
83102
```
84103

85-
Run the daemon (MOSS-Audio on Apple Silicon is the default profile):
104+
Start the singleton gateway, then open the agent or library:
86105

87106
```bash
88-
uv run oida --host 127.0.0.1 --port 8765 # add --profile stub for a model-free dev run
107+
uv run oida start # add --profile stub for model-free use
108+
uv run oida agent
109+
uv run oida agent --library
89110
```
90111

91-
Open the dashboard at `http://127.0.0.1:8765`.
112+
`oida` or `oida serve` still runs the same system in the foreground. The local
113+
dashboard is `http://127.0.0.1:8765`, the library is `/library/`, REST gateway
114+
discovery is `/gateway`, and streamable HTTP MCP is `/mcp`.
115+
116+
Install the local adapters (each host can then start/reuse Oída automatically):
117+
118+
```bash
119+
uv run oida integrate hermes
120+
uv run oida integrate codex
121+
uv run oida integrate claude
122+
uv run oida integrate remote --serve # private responsive UI via Tailscale
123+
uv run oida doctor
124+
```
125+
126+
No native iOS or cloud service is required: open the reported Tailscale URL on
127+
the phone to use it as the microphone, speaker, screen, and remote control.
92128

93129
Generate a normalized listening event:
94130

@@ -98,6 +134,11 @@ curl -s http://127.0.0.1:8765/listen-event \
98134
-d '{"path":"/path/to/clip.wav","route_preset":"basic"}'
99135
```
100136

137+
An audio-capable host can keep perception in its own model and send a declared
138+
report to `/gateway/harness`; see [the gateway contract](docs/gateway-contract.md)
139+
for the schema and examples. MOSS is therefore an optimized local backend, not
140+
a requirement for the harness path.
141+
101142
Routed local session, live ring buffer, and background runtime:
102143

103144
```bash
@@ -204,7 +245,11 @@ akousmata store is written only by the explicit germ handoff actions.
204245
(`PLAN.md` keeps the historical OIDA phases).
205246
- `docs/release-readiness.md` — what `scripts/run_local_checks.sh release`
206247
validates.
248+
- `docs/gateway-contract.md` — lifecycle, host-perception envelope, and local
249+
integration boundaries.
250+
- `integrations/` — the bundled Hermes, Codex, Claude, and remote adapters.
207251
- CI (`.github/workflows/ci.yml`) runs pytest, compileall, a JS syntax check,
208252
the Swift build (including strict concurrency), packaging, and the stub
209-
daemon release smoke. The `akousma` path dependency requires `earworm`
210-
checked out as a sibling.
253+
daemon release smoke. Development uses canonical sibling sources; the Oída
254+
distribution declares them as versioned dependencies so they are installed
255+
as one stack rather than copied into divergent forks.

docs/architecture/current-state.md

Lines changed: 24 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,21 @@
11
# Current Architecture: `oida` Base
22

3-
This document maps the current OIDA codebase that `oida` is being built from.
4-
The repository is already a working local listening daemon and AKOÚŌ harness;
5-
the next stage should wrap and extend these paths rather than replace them.
3+
This document maps the current Oída unified listening stack. Oída is both a
4+
listening agent and a harness layer for other audio-capable agents.
5+
6+
## Unified Stack And Gateway
7+
8+
One Oída installation resolves the canonical AKOÚŌ contract package,
9+
Earworm/akousma protocol package, and Akousmata navigator. One managed server
10+
exposes four coordinated surfaces: the Oída agent/dashboard, the
11+
`oida/gateway/v0.2` REST contract, official MCP over stdio or `/mcp`, and the
12+
Akousmata app mounted at `/library/`.
13+
14+
There are two perception paths. `oida_owned` sends accessible audio through
15+
Oída's selected engine and DSP. `host_supplied` accepts a model report from an
16+
audio-input-capable host, preserves that host's apparatus declaration, and
17+
routes its observations through the same AKOÚŌ and Earworm layers. MOSS-Audio
18+
is the optimized local model backend, not a gateway requirement.
619

720
## Project Shape
821

@@ -23,21 +36,20 @@ the next stage should wrap and extend these paths rather than replace them.
2336
- `oida/MOSS-Audio/` and `oida/weights/` are local model/runtime assets used by
2437
the Mac MPS profile. They are not app source.
2538

26-
The Python package remains `oida` internally for compatibility. The public app
27-
identity is moving to lowercase `oida`, with `oida` kept as a legacy alias.
39+
The Python package and CLI are `oida`; the accented public identity is **oída**.
40+
The historical `hmm` and `aear` commands remain compatibility aliases.
2841

2942
## Current Request Flow
3043

3144
```text
32-
dashboard / CLI / MCP
33-
-> FastAPI endpoint in oida.server
34-
-> oida.reporting task function
35-
-> MossEngine adapter
36-
-> MOSS-Audio output parsing
37-
-> DSP feature extraction
45+
dashboard / CLI / MCP / host plugin
46+
-> Oída gateway router
47+
-> Oída-owned audio: reporting -> selected audio engine + DSP
48+
OR host-owned perception: declared host report + apparatus
3849
-> PerceptionReport schema
3950
-> AKOÚŌ command output / claim mapping
40-
-> dashboard render, CLI journal, or JSON response
51+
-> Earworm session context (+ explicit Akousmata remember when requested)
52+
-> dashboard, CLI, host agent, library, journal, or JSON response
4153
```
4254

4355
## Audio File Flow

docs/gateway-contract.md

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
# Oída gateway contract
2+
3+
Oída is both a listening agent and a local listening layer for other agents.
4+
Installing Oída installs and exposes the complete stack: AKOÚŌ routing and
5+
claim discipline, Earworm event/provenance envelopes, and the Akousmata store
6+
and navigator.
7+
8+
The stable gateway contract is `oida/gateway/v0.2`. It supports two paths:
9+
10+
1. **Oída-owned perception** — pass Oída a local audio path. Its configured
11+
engine (MOSS-Audio when available, DSP-only stub otherwise) performs the
12+
perceptual passes. Oída returns the perception report, AKOÚŌ command output,
13+
normalized listening event, and an optional memory trace.
14+
2. **Host-supplied perception** — an audio-capable Hermes, Codex, Claude, or
15+
generic host describes what its active model heard using
16+
`oida/host-perception/v0.1`. Oída does not run MOSS again. It applies the
17+
same router, evidence permissions, claim taxonomy, Earworm provenance, and
18+
Akousmata memory flow.
19+
20+
Host perception must declare its apparatus when known. Sample rate, channel
21+
count, bandwidth, calibration, preprocessing, and blind spots determine which
22+
claims can be supported. An undeclared apparatus is accepted but explicitly
23+
marked undetermined. Model output can never become a `measured` claim merely
24+
because the model used a number; measurements need DSP, metadata, a measuring
25+
tool, or a declared human measurement.
26+
27+
## Lifecycle
28+
29+
- `oida` or `oida serve` runs the agent, REST gateway, dashboard, and mounted
30+
Akousmata navigator in one process.
31+
- `oida start` ensures the singleton local gateway is running in the background.
32+
- `oida gateway --stdio --ensure-daemon` is the MCP command for local agents.
33+
- `oida agent` ensures the gateway and opens its local interface.
34+
- `oida status`, `oida doctor`, and `oida stop` inspect or control the managed
35+
gateway.
36+
37+
Hermes, Codex, and Claude integrations always invoke the stdio gateway command,
38+
so they can start Oída when needed without loading a second MOSS model. A
39+
running daemon is reused. The local remote surface uses the same process and is
40+
intended for an operator-configured private network such as Tailscale; it is
41+
not a cloud application.
42+
43+
## Host input example
44+
45+
```json
46+
{
47+
"contract": "oida/host-perception/v0.1",
48+
"host": {
49+
"id": "codex",
50+
"model": "audio-capable-model",
51+
"session_id": "session-123",
52+
"audio_input_capable": true
53+
},
54+
"source": {
55+
"label": "attached field recording",
56+
"type": "file",
57+
"duration_s": 18.4,
58+
"audio_available_to_oida": false
59+
},
60+
"apparatus": {
61+
"substrate": "host_audio_model",
62+
"sample_rate_hz": 48000,
63+
"channels": 2,
64+
"bandwidth_limit_hz": 24000,
65+
"known_blind_spots": ["The host does not expose its resampling path."]
66+
},
67+
"observations": [
68+
{
69+
"statement": "A repeating metallic impact is audible.",
70+
"category": "heard",
71+
"confidence": "medium",
72+
"source": "model",
73+
"time_range": {"start_s": 2.1, "end_s": 7.8}
74+
}
75+
],
76+
"uncertainty": ["The source object cannot be identified from audio alone."]
77+
}
78+
```
79+
80+
See `oida/schemas/host-perception.schema.json` for the complete input schema.

harness/akouo/command.py

Lines changed: 20 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,18 @@
1111

1212

1313
def build_apparatus(report: dict[str, Any] | None = None) -> dict[str, Any]:
14-
"""AKOÚŌ v0.6 apparatus declaration for the oída stack: name the substrate and
15-
its structural blind spots so claim limits derive from the declared apparatus."""
14+
"""AKOÚŌ apparatus declaration for Oída or a host audio model."""
1615
report = report if isinstance(report, dict) else {}
16+
declared = report.get("apparatus") if isinstance(report.get("apparatus"), dict) else None
17+
if declared:
18+
apparatus = dict(declared)
19+
apparatus.setdefault("substrate", "host_audio_model")
20+
apparatus.setdefault("perception_sources", ["host-supplied audio perception"])
21+
apparatus.setdefault(
22+
"known_blind_spots",
23+
["The host did not declare complete acoustic preprocessing and calibration details."],
24+
)
25+
return apparatus
1726
engine = report.get("engine") if isinstance(report.get("engine"), dict) else {}
1827
perception_sources = ["oida DSP feature block (deterministic measurement)"]
1928
for key, label in (
@@ -54,18 +63,20 @@ def build_listening_output(
5463
recommended_next_mode: str = "undetermined",
5564
report: dict[str, Any] | None = None,
5665
) -> dict[str, Any]:
66+
apparatus = build_apparatus(report)
67+
sources = ", ".join(str(source) for source in apparatus.get("perception_sources", [])[:2]) or "machine perception"
5768
risks = empty_risks()
58-
risks["hallucination"].append("MOSS-Audio can overstate acoustic evidence; retain time anchors and uncertainty notes.")
69+
risks["hallucination"].append("Audio models can overstate acoustic evidence; retain time anchors and uncertainty notes.")
5970
risks["over_identification"].append("Source, speaker identity, age, accent, and emotion claims require caution.")
6071
mediations = empty_mediations()
61-
mediations["technical"].append("MOSS-Audio receives 16 kHz mono audio; DSP supplies measured signal features.")
62-
mediations["computational"].append("PerceptionReport evidence is model output plus deterministic DSP, not direct human listening.")
72+
mediations["technical"].append(f"Declared perception apparatus: {sources}.")
73+
mediations["computational"].append("PerceptionReport evidence is model output plus any declared measurements, not direct human listening.")
6374
return {
6475
"object_listened_to": object_listened_to,
6576
"input_type": "model_output",
6677
"listening_mode": mode,
6778
"akouo_version": AKOUO_OUTPUT_VERSION,
68-
"apparatus": build_apparatus(report),
79+
"apparatus": apparatus,
6980
"listener": {"type": "agent", "process": "agent_automated"},
7081
"listening_claims": claims,
7182
"what_appears": summarize_visible_claims(claims),
@@ -99,7 +110,7 @@ def build_command_output(report: dict[str, Any], command: str = "/listen", quest
99110
return {
100111
"command": command,
101112
"object_listened_to": object_listened_to,
102-
"input_type": "audio_file",
113+
"input_type": "model_output" if report.get("host") else "audio_file",
103114
"akouo_version": AKOUO_OUTPUT_VERSION,
104115
"skills_called": skills_called,
105116
"execution_order": skills_called,
@@ -108,8 +119,8 @@ def build_command_output(report: dict[str, Any], command: str = "/listen", quest
108119
"synthesis": synthesize_claims(claims, command),
109120
"claim_summary": claims,
110121
"risks": [
111-
"MOSS captions and paralinguistics are machine-heard evidence, not measurements.",
112-
"Contradictions between DSP and MOSS remain undetermined.",
122+
"Model captions and paralinguistics are machine-heard evidence, not measurements.",
123+
"Contradictions between declared measurements and model perception remain undetermined.",
113124
],
114125
"recommended_next_mode": route.recommended_next_mode,
115126
}

harness/akouo/loader.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,14 @@ def default_akouo_root() -> Path:
2121
for candidate in DEFAULT_AKOUO_CANDIDATES:
2222
if candidate and candidate.expanduser().exists():
2323
return candidate.expanduser().resolve()
24+
try:
25+
from akouo_contract import root as installed_root
26+
27+
packaged = installed_root()
28+
if packaged.exists():
29+
return packaged
30+
except (ImportError, OSError):
31+
pass
2432
return Path.home() / "Documents" / "SFL" / "akouo"
2533

2634

0 commit comments

Comments
 (0)