<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Emotion Recognition on Boris Dupoux</title><link>https://borisdupoux.com/tags/emotion-recognition/</link><description>Recent content in Emotion Recognition on Boris Dupoux</description><generator>Hugo -- gohugo.io</generator><language>en-us</language><lastBuildDate>Thu, 01 Oct 2026 00:00:00 +0000</lastBuildDate><atom:link href="https://borisdupoux.com/tags/emotion-recognition/index.xml" rel="self" type="application/rss+xml"/><item><title>A Fully Local AI Agent with a Meaning Graph and Multimodal Emotion Measurement</title><link>https://borisdupoux.com/research/local-ai-agent/</link><pubDate>Thu, 01 Oct 2026 00:00:00 +0000</pubDate><guid>https://borisdupoux.com/research/local-ai-agent/</guid><description>&lt;h2 id="context"&gt;&lt;a href="#context" class="header-anchor"&gt;&lt;/a&gt;Context
&lt;/h2&gt;&lt;p&gt;Personal digital traces (messaging, mail, photos, music listening, notes, calendar,
health exports, code repositories) are among the most sensitive data a person owns, and
also among the richest for studying behaviour — and feeling — over time. Sending them to
a cloud LLM is not acceptable, so everything here runs on a single Apple-silicon desktop
(M4, 32 GB unified memory), and no data leaves the machine.&lt;/p&gt;
&lt;p&gt;The aim is an agent that answers questions about one&amp;rsquo;s own life while keeping a strict
line between what is &lt;em&gt;observed&lt;/em&gt;, what is &lt;em&gt;computed&lt;/em&gt;, what is &lt;em&gt;hypothesised by a model&lt;/em&gt;,
and what is &lt;em&gt;accepted as true by its owner&lt;/em&gt;.&lt;/p&gt;
&lt;h2 id="what-is-original"&gt;&lt;a href="#what-is-original" class="header-anchor"&gt;&lt;/a&gt;What is original
&lt;/h2&gt;&lt;p&gt;Local agents over personal files are not new. Two aspects of this project are.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;1. A meaning graph on top of a measurement layer.&lt;/strong&gt; Knowledge is held at two levels.
An &lt;em&gt;observatory&lt;/em&gt; stores facts and signals in long format (item, dimension, value,
confidence, model, version). Above it, a &lt;strong&gt;meaning graph&lt;/strong&gt; stores what those signals
&lt;em&gt;mean&lt;/em&gt;: &lt;strong&gt;relations&lt;/strong&gt; (reified, so that a relationship can evolve and be measured),
&lt;strong&gt;affective episodes&lt;/strong&gt; (who felt what, when, how intensely, through which modality),
&lt;strong&gt;themes&lt;/strong&gt;, &lt;strong&gt;chapters&lt;/strong&gt; of a life, and &lt;strong&gt;truths&lt;/strong&gt; — statements with supporting and
contradicting evidence that only the owner can validate. Every node and edge carries its
provenance down to the source element, and an origin ranked by trust
(human &amp;gt; declared &amp;gt; structural &amp;gt; rule/computed &amp;gt; vendor &amp;gt; model &amp;gt; inferred).&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;2. Emotion measured across modalities, along unusual dimensions.&lt;/strong&gt; The same fixed
vocabulary of &lt;strong&gt;53 emotions&lt;/strong&gt; (Plutchik-based, each with valence and arousal coordinates)
is applied to &lt;strong&gt;messages&lt;/strong&gt; (local LLM), &lt;strong&gt;voice&lt;/strong&gt; (five acoustic and multimodal layers
fused with the transcript, with an explicit text/voice &lt;em&gt;mismatch&lt;/em&gt; flag) and &lt;strong&gt;photos&lt;/strong&gt;
(deterministic colour and light measures, SigLIP embeddings, face signals treated as weak
evidence). These sit in a catalogue of &lt;strong&gt;929 dimensions in 88 groups&lt;/strong&gt; that goes well
beyond the usual metadata. A few examples of its less common entries:&lt;/p&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;modality&lt;/th&gt;
					&lt;th&gt;dimension&lt;/th&gt;
					&lt;th&gt;how it is defined&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;photo&lt;/td&gt;
					&lt;td&gt;colour temperature&lt;/td&gt;
					&lt;td&gt;mean red–blue balance of the image (warm vs cool)&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;photo&lt;/td&gt;
					&lt;td&gt;colourfulness&lt;/td&gt;
					&lt;td&gt;Hasler &amp;amp; Süsstrunk (2003) opponent-colour metric&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;photo&lt;/td&gt;
					&lt;td&gt;golden hour / blue hour&lt;/td&gt;
					&lt;td&gt;sun elevation computed offline from date and position&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;photo&lt;/td&gt;
					&lt;td&gt;face size&lt;/td&gt;
					&lt;td&gt;share of the frame taken by a face (a proxy for proximity)&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;voice&lt;/td&gt;
					&lt;td&gt;jitter, shimmer, harmonics-to-noise ratio&lt;/td&gt;
					&lt;td&gt;openSMILE eGeMAPS prosody&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;voice&lt;/td&gt;
					&lt;td&gt;laughter, crying, sighs&lt;/td&gt;
					&lt;td&gt;sound-event detection (AudioSet classes)&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;voice&lt;/td&gt;
					&lt;td&gt;text/voice mismatch&lt;/td&gt;
					&lt;td&gt;voice valence and transcript valence differ by ≥ 0.6&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;message&lt;/td&gt;
					&lt;td&gt;valence, arousal, tone&lt;/td&gt;
					&lt;td&gt;per participant, constrained to the fixed grid&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;message&lt;/td&gt;
					&lt;td&gt;expressive punctuation, emoji palette&lt;/td&gt;
					&lt;td&gt;deterministic text measures&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;relation&lt;/td&gt;
					&lt;td&gt;reply-latency asymmetry&lt;/td&gt;
					&lt;td&gt;log ratio of the two parties&amp;rsquo; median reply delays&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;relation&lt;/td&gt;
					&lt;td&gt;initiatives&lt;/td&gt;
					&lt;td&gt;conversations opened after 3 h of silence, per side&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;relation&lt;/td&gt;
					&lt;td&gt;trend&lt;/td&gt;
					&lt;td&gt;slope of relationship intensity over 90 days (cooling &amp;lt; 0)&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;period&lt;/td&gt;
					&lt;td&gt;musical nostalgia&lt;/td&gt;
					&lt;td&gt;mean age of the tracks listened to&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;period&lt;/td&gt;
					&lt;td&gt;creation / consumption&lt;/td&gt;
					&lt;td&gt;time in creative tools ÷ time consuming&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id="from-signals-to-meaning"&gt;&lt;a href="#from-signals-to-meaning" class="header-anchor"&gt;&lt;/a&gt;From signals to meaning
&lt;/h2&gt;&lt;pre class="mermaid" style="visibility:hidden"&gt;flowchart LR
 PH["Photo"] --&gt; PM["Measures&lt;br/&gt;light · contrast · colour temperature&lt;br/&gt;colourfulness · palette · sharpness"]
 PH --&gt; PS["SigLIP embedding&lt;br/&gt;(image ↔ text similarity)"]
 PH --&gt; PF["Vendor face signals&lt;br/&gt;smile · expression · gaze · face size"]
 VN["Voice note"] --&gt; VT["Whisper transcript"]
 VN --&gt; VL["Acoustic layers&lt;br/&gt;valence/arousal/dominance · categories&lt;br/&gt;sound events · prosody · audio-LLM"]
 VT --&gt; VX["Text emotion of transcript"]
 VL --&gt; VF["Weighted fusion&lt;br/&gt;confidence = agreement&lt;br/&gt;text/voice mismatch flag"]
 VX --&gt; VF
 MS["Messages&lt;br/&gt;(pseudonymised: Me, P1, P2)"] --&gt; ML["Local LLM, fixed grid&lt;br/&gt;emotion · intensity · valence&lt;br/&gt;arousal · tone · topics"]
 PM --&gt; OB[("Observatory&lt;br/&gt;929 dimensions")]
 PS --&gt; OB
 PF --&gt; OB
 VF --&gt; OB
 ML --&gt; OB
 OB -- "emotion with enough confidence" --&gt; AFF["Affective episode (AFF)&lt;br/&gt;who · emotion · when · intensity · modality"]
 PF -. "weak cue, confidence ≤ 0.4" .-&gt; AFF
 ML -- "topics" --&gt; THM["Themes"]
 OB -- "aggregates" --&gt; AG["Day / period indicators&lt;br/&gt;valence · light · palette"]
 AFF --&gt; G["Meaning graph&lt;br/&gt;relations · episodes · themes · chapters · truths&lt;br/&gt;(all proposed)"]
 THM --&gt; G
 AG --&gt; G
 G --&gt; HV(("Owner&lt;br/&gt;validate · reject · correct"))&lt;/pre&gt;&lt;p&gt;Each affective episode is a node linked to the person who felt it, to the emotion in the
fixed vocabulary, and — when it exists — to the conversation or moment it occurred in.
Inference rules then carry affect upwards (for instance, the affect of a chapter or of a
routine), and strong aggregate correlations can become &lt;em&gt;proposed&lt;/em&gt; truths with their
measures as evidence.&lt;/p&gt;
&lt;h2 id="emotion-measurement-in-detail"&gt;&lt;a href="#emotion-measurement-in-detail" class="header-anchor"&gt;&lt;/a&gt;Emotion measurement in detail
&lt;/h2&gt;&lt;p&gt;&lt;strong&gt;Vocabulary.&lt;/strong&gt; The grid is fixed and versioned: Plutchik&amp;rsquo;s 8 primary emotions at 3
intensities, his 8 primary dyads, plus social and reflective emotions useful for a life
(gratitude, tenderness, pride, shame, loneliness, nostalgia, wonder, relief, exhaustion…),
&lt;strong&gt;53 in total&lt;/strong&gt;. Each carries starting coordinates in Russell&amp;rsquo;s circumplex — valence in
[−1, 1], arousal in [0, 1] — meant to be calibrated later on the owner&amp;rsquo;s own validations.
Plutchik oppositions are encoded, and health-app mood labels are mapped onto the grid.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Messages.&lt;/strong&gt; A local LLM (Qwen3-30B-A3B) reads each conversation with participants
replaced by &amp;ldquo;Me&amp;rdquo;, &amp;ldquo;P1&amp;rdquo;, &amp;ldquo;P2&amp;rdquo;, messages framed as data it must not obey, and media
reduced to placeholders such as &amp;ldquo;[voice note 23 s]&amp;rdquo;. Output is constrained by a JSON
schema: for each participant, the dominant emotion from the grid (or none), intensity,
valence, arousal, a tone from a closed list of 19, and a confidence; plus 1–3 topics
that become themes. Long conversations are reduced to their beginning and end; short
ones are batched ten per call. An affective episode is proposed only when confidence is
at least 0.3.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Voice.&lt;/strong&gt; Each recording is converted to 16 kHz mono and passes through:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Whisper large-v3-turbo (MLX) for the transcript;&lt;/li&gt;
&lt;li&gt;a wav2vec2 dimensional model giving valence, arousal and dominance on 15 s windows,
weighted by window length, plus arousal variability;&lt;/li&gt;
&lt;li&gt;emotion2vec+ large for categorical emotion, mapped onto the grid (kept at ≥ 0.4);&lt;/li&gt;
&lt;li&gt;an AST AudioSet classifier for laughter, crying, sighs, shouting, whispering, music
and ambience;&lt;/li&gt;
&lt;li&gt;openSMILE eGeMAPS prosody: pitch (semitones) and its variability, loudness, jitter,
shimmer, harmonics-to-noise ratio, voiced segments per second, mean pause length;&lt;/li&gt;
&lt;li&gt;Qwen2.5-Omni-7B (llama.cpp, Metal), which listens to the audio and returns an emotion
from the grid, a valence and short acoustic cues;&lt;/li&gt;
&lt;li&gt;the text-emotion model above, applied to the transcript.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The categorical opinions (voice categories, audio-LLM, transcript) are combined by a
weighted vote (weights 1.0, 1.0 and 0.8); valence is a weighted mean of the dimensional
model, the audio-LLM and the transcript. &lt;strong&gt;Confidence is agreement between layers&lt;/strong&gt;: one
agreeing source gives 0.45, two give 0.65, three give 0.85, minus 0.1 for each source
that disagrees. When the voice and the words disagree by 0.6 or more in valence (an
&amp;ldquo;I&amp;rsquo;m fine&amp;rdquo; said sadly), a &lt;strong&gt;text/voice mismatch&lt;/strong&gt; is flagged rather than averaged away.
Laughter and crying scores are kept alongside.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Photos.&lt;/strong&gt; On 256 px thumbnails, without any model: luminance, contrast, saturation,
colour temperature, colourfulness, sharpness (variance of the Laplacian) and a 5-colour
palette with named dominant hue. SigLIP so400m embeddings make the library searchable by
text. Vendor face attributes (smile, smile type, expression, gaze, eye state, face size)
are read as signals, but the schema states that &lt;em&gt;a photographed smile is not a felt joy&lt;/em&gt;:
the face modality is a weak cue whose confidence is capped at 0.4. Music mood is handled
the same way: the mood of a track is never, on its own, evidence of the listener&amp;rsquo;s mood.
At period level, valence is fused with a fixed precedence: declared &amp;gt; voice &amp;gt; text &amp;gt; face.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Human validation.&lt;/strong&gt; Every episode, theme, chapter or truth is emitted as &lt;code&gt;proposed&lt;/code&gt;.
The PWA shows a validation queue — affective episodes ordered by confidence, with the
evidence (the conversation or recording it came from) — and the owner validates, rejects
or corrects. Only that human decision event turns a proposal into &lt;code&gt;validated&lt;/code&gt;, an
equivalence checked automatically. The planned next step is a small personal classifier
on emotion2vec features, trained on these validations.&lt;/p&gt;
&lt;h2 id="architecture"&gt;&lt;a href="#architecture" class="header-anchor"&gt;&lt;/a&gt;Architecture
&lt;/h2&gt;&lt;pre class="mermaid" style="visibility:hidden"&gt;flowchart TB
 S["Sources (read-only snapshots)&lt;br/&gt;messaging · mail · photos · music · notes · calendar · exports"]
 C["Connectors&lt;br/&gt;dedicated ingestion process, sole holder of disk access"]
 V["Vault (owner-only, 0700)&lt;br/&gt;content-addressed raw store"]
 O["Observatory&lt;br/&gt;facts + signals (SQLite)"]
 K["Meaning graph&lt;br/&gt;append-only JSONL log → SQLite fold + FTS"]
 N["Nightly / hourly pipelines&lt;br/&gt;thumbnails · measures · SigLIP · emotions&lt;br/&gt;(GPU lock, one model at a time)"]
 M["MCP server (stdio, no port)&lt;br/&gt;20 read-only / propose-only tools"]
 H["Hermes Agent&lt;br/&gt;local LLM via Ollama"]
 P["PWA (HTTPS + TOTP)&lt;br/&gt;chat · validation queue"]
 U(("Owner"))
 S --&gt; C --&gt; V --&gt; O --&gt; K
 N --&gt; O
 O --&gt; M
 K --&gt; M
 M --&gt; H --&gt; P
 P -- "validate / reject / correct" --&gt; K
 U -- "NetBird VPN" --&gt; P&lt;/pre&gt;&lt;p&gt;Raw data is snapshotted (SQLite opened in &lt;code&gt;mode=ro&amp;amp;immutable=1&lt;/code&gt;) and never written to;
everything derived lives in a separate owner-only vault, and the code repository holds no
data. The meaning graph is built on the atoms library&amp;rsquo;s knowledge-base module: an
append-only, schema-validated JSONL event log folded into a disposable SQLite index.&lt;/p&gt;
&lt;p&gt;The schema itself is data, verified mechanically: &lt;strong&gt;27 node types and 50 predicates&lt;/strong&gt;,
&lt;strong&gt;9 provenance origins&lt;/strong&gt;, &lt;strong&gt;31 locator kinds&lt;/strong&gt; tying every claim to its source element,
the 53-emotion vocabulary, &lt;strong&gt;17 inference rules&lt;/strong&gt;, and &lt;strong&gt;42 sources&lt;/strong&gt; behind the 929
dimensions (610 native, 126 vendor-computed, 86 aggregates, 74 deterministic measures,
29 model interpretations).&lt;/p&gt;
&lt;h2 id="security-model"&gt;&lt;a href="#security-model" class="header-anchor"&gt;&lt;/a&gt;Security model
&lt;/h2&gt;&lt;p&gt;Source content is assumed adversarial (prompt injection in a message or mail), and the
model may hallucinate or misuse tools. Defences are structural:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;No ambient capabilities.&lt;/strong&gt; The agent framework (Hermes Agent) has 20 built-in
toolsets disabled (terminal, files, code execution, web, browser, delegation, memory,
cloud speech…); no cloud provider, update check or external login; the only model
endpoint is a loopback Ollama server.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;One narrow interface.&lt;/strong&gt; Data is reachable only through a local MCP server over stdio,
with closed schemas, validated arguments, explicit truncation and a content-free access
log. Tools can &lt;em&gt;propose&lt;/em&gt;, never &lt;em&gt;decide&lt;/em&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Privilege separation and pseudonymisation.&lt;/strong&gt; Only ingestion holds full-disk access;
analysis has no network. Third parties are opaque codes, and a real name in an
identifier is rejected by the schema.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Sensitivity levels&lt;/strong&gt; (0–3) per element with a lower ceiling for remote sessions;
remote access only through a NetBird VPN, TOTP and strict session cookies.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Ethical exclusions&lt;/strong&gt;: vendor-inferred ethnicity, skin tone and gender are never read.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="models"&gt;&lt;a href="#models" class="header-anchor"&gt;&lt;/a&gt;Models
&lt;/h2&gt;&lt;p&gt;All inference is local; one large model is loaded at a time under a shared GPU lock.&lt;/p&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;task&lt;/th&gt;
					&lt;th&gt;model&lt;/th&gt;
					&lt;th&gt;runtime&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;agent (tool use, ≥ 64k context)&lt;/td&gt;
					&lt;td&gt;gpt-oss:20b, qwen3:8b fallback&lt;/td&gt;
					&lt;td&gt;Ollama&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;text emotions, voice-transcript emotions&lt;/td&gt;
					&lt;td&gt;Qwen3-30B-A3B-Instruct-2507 (Q4)&lt;/td&gt;
					&lt;td&gt;Ollama&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;text / image embeddings&lt;/td&gt;
					&lt;td&gt;bge-m3 · SigLIP so400m&lt;/td&gt;
					&lt;td&gt;Ollama · PyTorch MPS&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;image reading&lt;/td&gt;
					&lt;td&gt;qwen3-vl:8b&lt;/td&gt;
					&lt;td&gt;Ollama&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;speech-to-text&lt;/td&gt;
					&lt;td&gt;Whisper large-v3-turbo&lt;/td&gt;
					&lt;td&gt;MLX&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;voice emotion (5 layers)&lt;/td&gt;
					&lt;td&gt;wav2vec2 dimensional · emotion2vec+ · AST · openSMILE eGeMAPS · Qwen2.5-Omni-7B&lt;/td&gt;
					&lt;td&gt;PyTorch MPS · CPU · llama.cpp (Metal)&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Each model is smoke-tested on synthetic data only (a fictitious French sentence
synthesised by a local TTS, then passed through the whole audio chain).&lt;/p&gt;
&lt;h2 id="evaluation--results"&gt;&lt;a href="#evaluation--results" class="header-anchor"&gt;&lt;/a&gt;Evaluation &amp;amp; results
&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Agent answer quality.&lt;/strong&gt; A 16-question benchmark (2 trap questions), with ground truth
computed by calling the tools directly, scores tool choice, &lt;em&gt;numerical fidelity&lt;/em&gt; (every
number in the answer must appear in that turn&amp;rsquo;s tool outputs), correctness, trap
handling and partial-period flagging: &lt;strong&gt;73 % → 100 %&lt;/strong&gt; after tool-description,
argument-validation and configuration fixes.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Server-side error correction.&lt;/strong&gt; With a reduced 8-tool interface, simple questions
went from 76 % to 90 % and cross-source questions from 73 % to 90 %; 20 deliberately
unusual questions scored 89 % and exposed silent-zero failures, since fixed.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Context and latency.&lt;/strong&gt; Tool descriptions cut from 23.5 k to 9.5 k characters; a heavy
aggregate query from 172 s to 0.1 s; all heavy benchmark queries ≤ 0.3 s.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Cross-exploration benchmark.&lt;/strong&gt; 60 placeholder-only scenarios with oracle code; oracles
pass 61/61, with no leak at remote sensitivity ceilings 1 and 2.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Verification.&lt;/strong&gt; 56 named schema checks green; 631 native/vendor columns confirmed
against real database structures; 1,235 Python unit tests, 15 JavaScript test files and
110 quality tests on real data that report counts only.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="limitations--next-steps"&gt;&lt;a href="#limitations--next-steps" class="header-anchor"&gt;&lt;/a&gt;Limitations &amp;amp; next steps
&lt;/h2&gt;&lt;p&gt;Evaluation sets are small and authored by the system&amp;rsquo;s designer; they measure fidelity
and regressions rather than general capability. Emotion outputs are hypotheses: the
valence/arousal coordinates of the vocabulary are starting values, and personal
calibration of voice emotion from validated examples is still pending, as is the larger
target agent model. Agent answers take tens of seconds on a 20B model.&lt;/p&gt;
&lt;h2 id="stack"&gt;&lt;a href="#stack" class="header-anchor"&gt;&lt;/a&gt;Stack
&lt;/h2&gt;&lt;p&gt;&lt;code&gt;Python&lt;/code&gt; · &lt;code&gt;SQLite / FTS5&lt;/code&gt; · &lt;code&gt;Ollama&lt;/code&gt; · &lt;code&gt;llama.cpp (Metal)&lt;/code&gt; · &lt;code&gt;MLX&lt;/code&gt; · &lt;code&gt;PyTorch MPS&lt;/code&gt; · &lt;code&gt;Hermes Agent&lt;/code&gt; · &lt;code&gt;MCP&lt;/code&gt; · &lt;code&gt;SigLIP&lt;/code&gt; · &lt;code&gt;Whisper&lt;/code&gt; · &lt;code&gt;emotion2vec&lt;/code&gt; · &lt;code&gt;openSMILE&lt;/code&gt; · &lt;code&gt;NetBird&lt;/code&gt; · &lt;code&gt;PWA&lt;/code&gt; · &lt;code&gt;launchd&lt;/code&gt;&lt;/p&gt;</description></item></channel></rss>