Maps a detected user emotion — from facial expression (emotion.detected) OR speech (speechemotion.detected) — into a mood signal logged via the Mood skill, then picks one response route (music /…
Apache-2.0Auto-check passed
Install User Emotion Detection
skills CLI
$ npx skills add autonomous-ai/Physical-AI-Operating-System --skill user-emotion-detection -a claude-code
Project install by default; add -g for ~/.claude/skills/.
Install the "user-emotion-detection" agent skill from https://github.com/autonomous-ai/Physical-AI-Operating-System/tree/main/skills/user-emotion-detection into .claude/skills/user-emotion-detection/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "user-emotion-detection", then confirm the skill loads.
Claude Code copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
Type this inside Codex. $skill-installer <name> installs a curated skill from openai/skills. The installer writes to $CODEX_HOME/skills (default ~/.codex/skills). Restart Codex if the skill does not show up.
skills CLI
$ npx skills add autonomous-ai/Physical-AI-Operating-System --skill user-emotion-detection -a codex
Project install goes to .agents/skills/; add -g for ~/.codex/skills/.
Install the "user-emotion-detection" agent skill from https://github.com/autonomous-ai/Physical-AI-Operating-System/tree/main/skills/user-emotion-detection into .agents/skills/user-emotion-detection/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "user-emotion-detection", then confirm the skill loads.
Codex copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
skills CLI
$ npx skills add autonomous-ai/Physical-AI-Operating-System --skill user-emotion-detection -a cursor
Project install goes to .agents/skills/; add -g for ~/.cursor/skills/.
Install the "user-emotion-detection" agent skill from https://github.com/autonomous-ai/Physical-AI-Operating-System/tree/main/skills/user-emotion-detection into .cursor/skills/user-emotion-detection/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "user-emotion-detection", then confirm the skill loads.
Cursor copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
--scope user (default) or --scope workspace; --path is the subfolder of the repo that holds the skill; --consent skips the security confirmation prompt.
skills CLI
$ npx skills add autonomous-ai/Physical-AI-Operating-System --skill user-emotion-detection -a gemini-cli
Project install goes to .agents/skills/; add -g for ~/.gemini/skills/.
Install the "user-emotion-detection" agent skill from https://github.com/autonomous-ai/Physical-AI-Operating-System/tree/main/skills/user-emotion-detection into .gemini/skills/user-emotion-detection/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "user-emotion-detection", then confirm the skill loads.
Gemini CLI copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
Installs for Copilot at project scope by default; add --scope user for a personal install. Preview a skill first with gh skill preview. Needs GitHub CLI 2.90.0 or later (public preview).
skills CLI
$ npx skills add autonomous-ai/Physical-AI-Operating-System --skill user-emotion-detection -a github-copilot
Project install goes to .agents/skills/; add -g for ~/.copilot/skills/.
Install the "user-emotion-detection" agent skill from https://github.com/autonomous-ai/Physical-AI-Operating-System/tree/main/skills/user-emotion-detection into .github/skills/user-emotion-detection/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "user-emotion-detection", then confirm the skill loads.
GitHub Copilot copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
skills CLI
$ npx skills add autonomous-ai/Physical-AI-Operating-System --skill user-emotion-detection -a opencode
OpenCode documents no install command of its own. Project install goes to .agents/skills/; add -g for ~/.config/opencode/skills/.
Install the "user-emotion-detection" agent skill from https://github.com/autonomous-ai/Physical-AI-Operating-System/tree/main/skills/user-emotion-detection into .opencode/skills/user-emotion-detection/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "user-emotion-detection", then confirm the skill loads.
OpenCode copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
Facts
Skill name
user-emotion-detection
GitHub stars
381
Token cost
~3.4k tokens
SKILL.md length
1,776 words
Files
3
Skills in repo
28
Repo updated
First seen
Licence
Apache-2.0
At a glance
Maps a detected user emotion — from facial expression (emotion.detected) OR speech (speechemotion.detected) — into a mood signal logged via the Mood skill, then picks one response route (music /…
Works in 2 steps: The mood signal source field — "camera"… → The label vocabulary — face uses…
SKILL.md covers Strict Trigger, What this skill does, Trigger and Emotion → mood (for the signal…, plus 4 more sections
Instructions only: no scripts, shell commands, URLs or credentials in SKILL.md
What it does
User Emotion Detection is an agent skill from autonomous-ai/Physical-AI-Operating-System. Maps a detected user emotion — from facial expression (emotion.detected) OR speech (speechemotion.detected) — into a mood signal logged via the Mood skill, then picks one response route (music / checkin / action). This is about the USER's emotion (input), NOT the device's own expression — that's emotion/SKILL.md.
Its SKILL.md is about 3.4k tokens, which your agent loads only when the skill is triggered. The skill folder holds 3 other files (for example `reference/checkin.md` and `skill.json`).
The repository describes itself as: The open-source operating system for physical AI. The licence is Apache-2.0.
Example prompts
“s emotion (input), NOT the device”
“/user-emotion-detection”
Workflow steps
2 steps, taken from the first numbered list in SKILL.md.
1The mood signal source field — "camera" for [emotion], "voice" for [speech_emotion].
2The label vocabulary — face uses Fear/Surprise/Disgust, voice uses Fearful/Surprised/Disgusted. The mapping table below covers both; they…
What it can do on your machine
Read from SKILL.md and the folder at commit 1bbd649. It shows what the files ask for, not the result of running them.
Tool permissions
Pre-approves nothing: there is no allowed-tools line, so your agent's usual permission prompts apply.
From allowed-tools in the SKILL.md frontmatter.
Runs code
No scripts in the folder and no shell commands in SKILL.md.
From the folder's file list and the shell code blocks in SKILL.md.
Network
No URLs in SKILL.md.
From URLs in SKILL.md, links to its own repository left out.
Credentials
Names no API keys, tokens, secrets or passwords.
From names ending in _API_KEY, _TOKEN, _SECRET, _KEY or _PASSWORD in SKILL.md.
Context cost
User Emotion Detection loads about 3.4k tokens when it runs. Until then it costs about 85 tokens; SKILL.md has 1,776 words of instructions outside code blocks.
Always· name and description, kept in context so the agent knows when to use it
~85
When it runs· the whole SKILL.md, loaded when a task matches
~3.4k
Estimates: characters ÷ 4, the usual rule of thumb; real counts depend on the model's tokenizer. Scripts and assets cost tokens only if the agent reads them.
Safety
Auto-check passed
The automated check found no risky patterns in SKILL.md.
Automated static check — not a guarantee. Review scripts before installing. It scans the text of SKILL.md for risky patterns (piping downloads into a shell, reading credential files, hidden Unicode, destructive commands); files beside SKILL.md are not scanned.
Download SKILL.mdSave it as .claude/skills/user-emotion-detection/SKILL.md (or your agent's skills folder). This skill also uses 2 other files; get the full folder from GitHub.
name
user-emotion-detection
description
Maps a detected user emotion — from facial expression (emotion.detected) OR speech (speech_emotion.detected) — into a mood signal logged via the Mood skill, then picks one response route (music / checkin / action). This is about the USER's emotion (input), NOT the device's own expression — that's emotion/SKILL.md.
User Emotion Detection
Strict Trigger
Runs only when this turn's input has one of:
[emotion] Emotion detected: <EmotionName> — facial expression from camera.
[speech_emotion] Speech emotion detected: <EmotionName> — vocal expression from microphone.
Both are first-class triggers and route through the same logic below. The only differences are:
The mood signal source field — "camera" for [emotion], "voice" for [speech_emotion].
The label vocabulary — face uses Fear/Surprise/Disgust, voice uses Fearful/Surprised/Disgusted. The mapping table below covers both; they bucket identically.
For any other event ([sensing:presence.*], [activity], [sensing:sound], [sensing:light.*], …) → STOP. No tool calls. Don't infer emotion from older turns — every signal must come from a real [emotion] or [speech_emotion] event in THIS turn.
EXECUTE, don't plan. Before any reply (including NO_REPLY) you MUST embed a [HW:/mood/log:{...}] marker in the reply for this event (it fires the POST async via the runtime — see "What this skill produces" below). Writing "I will post a mood signal" in thinking is not enough — if no [HW:/mood/log:...] marker appears in the reply text this turn, the skill failed. Every emotion.detected / speech_emotion.detected event = at least one mood signal log. No exceptions, no skips, no "already logged recently" reasoning. (curl POST is the documented fallback only when the HW marker would break the body regex; do not use it as the default.)
Logging has no spoken narration. Only the selected response route supplies speech or NO_REPLY. Never narrate mood logging, mapping, skill selection or workflow steps. Keep analysis in a separate reasoning channel; if none is available, omit analysis entirely.
When thinking is enabled, keep channels separate. Use only the provider's
native thinking/reasoning channel for route comparisons, cooldown checks,
uncertainty, style selection, and marker construction. Enabling thinking does
not permit a reasoning summary in assistant text. Every ordinary text/content
block can be spoken, including text before a tool call and text in the final
response. Do not put <think> tags or a heading such as Thinking: into text
as a substitute for the native channel. If that channel is unavailable, omit
the analysis. Call required tools directly with no text introduction; after
their results, emit only the required markers and the user-facing sentence.
EMOTION TURN OUTPUT CONTRACT — highest priority. For a triggered
[emotion] / [speech_emotion] turn, send no assistant-text preamble before
or between skill/tool calls. Your entire final assistant message
must be exactly one of these two shapes:
text
[required mood signal and selected-route HW markers] NO_REPLY
[required mood signal and selected-route HW markers] <one natural sentence addressed to the user, at most 20 words>
Nothing may appear before, between, or after those parts. In particular, do
not output the detected label or confidence; describe the cue as weak;
name a bucket, route, rule, source, prefix, marker, log, decision, or mood;
state what you are about to do; draft a line; or count its words/sentences.
Those are private scratch work, never user-facing text. Do the writes via HW
markers, then start immediately with the first word the user should hear.
Bad: Emotion: Anger. Weak camera cue. Route = checkin. Let me compose...
Good: [HW:...] That sounds rough — I'm right here.
After reading the selected route's reference, emit its required markers and the
spoken sentence, then end the turn. Do not reread the reference to refine the
wording. Silently check that removing the markers leaves only the sentence or
NO_REPLY; delete all planning prose, including An emotion event, Let me check, Let me route, and Let me combine them all. Never announce this check.
Also omit Route falls to checkin, music cooldown active, Weak sad cue,
comfort/invite tone, and Mood signal must be logged. These are routing notes,
not part of a checkin, even when followed by a valid spoken sentence. Do not
repeat or summarize native thinking in the final text.
When the input explicitly says weak camera cue or weak voice cue, do not
assert the detected feeling or a visible expression as fact. In a positive
checkin, use a neutral invitation instead of assuming happiness or a smile.
Keep the signal log and routing rules unchanged; uncertainty affects phrasing,
not whether to log the event.
What this skill does
On every [emotion] or [speech_emotion] event, turn the detected user emotion into a mood signal. Log it via the Mood skill, then route a response (music / checkin / action) based on the pre-fetched context.
This skill does NOT:
Fire [HW:/emotion:…] markers. Emotion expression is emotion/SKILL.md's job, driven by conversation context — not auto-mapped from a sensor reading.
Require a spoken reply. Whether to speak is decided by the normal reply rules (SOUL + sensing SKILL), not by this skill.
Write to the wellbeing log. Wellbeing is for physical activity (drink/break/celebrate/sedentary); emotions live in the mood log.
Face FER labels: Happy, Sad, Angry, Fear, Surprise, Disgust, Neutral.
Voice emotion2vec labels: Happy, Sad, Angry, Fearful, Surprised, Disgusted, Neutral (plus Other, <unk> — dropped upstream).
Both formats end with the same <EmotionName>. anchor; the same regex parses either one.
Emotion → mood (for the signal log)
Both label vocabularies map to the same mood values — voice variants (Fearful, Surprised, Disgusted) bucket identically to their face counterparts (Fear, Surprise, Disgust).
Detected emotion (face OR voice)
mood value to log
Happy
happy
Sad
sad
Angry
frustrated
Fear / Fearful
stressed
Surprise / Surprised
excited
Disgust / Disgusted
frustrated
Neutral
normal
What this skill produces
A single kind=signal row in the mood log, emitted as an HW marker at the start of your spoken reply (the runtime fires the POST async, no tool turn):
source is decided by the event prefix on THIS turn:
[emotion] → "camera"
[speech_emotion] → "voice"
Don't override based on prior turns or the recent_signals block; the prefix is authoritative.
mapped_mood comes straight from the [emotion_context: ...] block — do NOT look it up from the table on the fly. Every detected emotion in the mapping table gets logged (including Neutral → normal) — Mood needs the recency for decision synthesis. Use "unknown" when the context tag is missing.
Do NOT use curl exec for this signal log — see mood/SKILL.md's "What to write" section for the rationale (HW marker is single-trip, curl burns a tool turn). If no [HW:/mood/log:...] marker appears in the reply this turn, the skill failed.
Show full SKILL.md (762 more words)Show less
Combined with mood + music-suggestion
The backend injects this turn with an [emotion_context: {...JSON...}] block that pre-computes everything the three skills need (this skill is the router, mood logs the decision, music-suggestion fires only when this router picks the music route). Do NOT fire any read tool calls — the data is already in the message.
Pre-fetched fields (use directly):
mapped_mood — already maps this turn's <EmotionName> per the table above. This is the value to log as the signal mood. You no longer need to look it up yourself.
recent_signals, prior_decision, is_decision_stale — feed mood/SKILL.md's decision rules and this skill's routing table.
audio_playing, last_suggestion_age_min, audio_recent, music_pattern_for_hour, suggestion_worthy — feed this skill's routing table (see Response routing below) and music-suggestion/SKILL.md's genre pick.
Single combined plan, not three sequential workflows:
Decide locally — apply mood decision rules from mood/SKILL.md; pick a route from the routing table below; if the route is music, evaluate genre from music-suggestion/SKILL.md.
Writes (inline markers in the same reply) — emit the mood signal marker (this skill), the mood decision marker when required by the mood rules, and on music or checkin route, the music-suggestion log marker (the shared cooldown channel). Use the marker shapes in the respective skills; do not also POST these logs through a shell. Preserve the selected route's speech or NO_REPLY after the markers.
Fallback (only if [emotion_context: ...] is missing)
If the message has no context block (pre-fetch failed), fall back to the read batch from mood/SKILL.md and music-suggestion/SKILL.md (concurrent GETs in one bash via & ... wait).
Reply: routing decides the spoken reply (see next section). Never narrate the mapping, logging, or routing decision.
Response routing (this skill is the router)
After logging the mood signal, pick exactly one response route. Read straight from [emotion_context: ...] — no extra tool calls. Apply top-to-bottom, first match wins:
#
Condition
Route
What happens
1
audio_playing == true
action
LED-only ambient ack, no spoken reply. Emit [HW:/emotion:{"emotion":"caring","intensity":0.4}] + NO_REPLY. Music is already covering — don't talk over it.
2
suggestion_worthy == true AND (is_decision_stale == false OR fresh decision synthesized this turn) AND last_suggestion_age_min ∉ [0, 7)
music
See music-suggestion/SKILL.md for genre + phrasing + log marker.
3
anything else (cooldown active, mood not worthy, stale decision with no fresh synthesis, mapped_mood normal/frustrated, etc.)
checkin
See reference/checkin.md for phrasing + log marker. One soft open-ended line.
Rules:
One route per turn. Don't double-fire (e.g. music + checkin both). Pick the first matching row.
Cooldown only gates music, not checkin. When last_suggestion_age_min ∈ [0, 7) the music branch is blocked (row #2 fails its third clause) and the event falls through to checkin (row #3). The agent still asks — it just doesn't suggest music back-to-back. The only NO_REPLY path is row #1 (active audio).
Output ownership:music → produced by music-suggestion/SKILL.md. checkin → produced by reference/checkin.md (this skill). action → emitted inline by this router (the [HW:/emotion:...] marker in row #1).
Cooldown is shared between music and checkin: both log via music-suggestion/log so last_suggestion_age_min reflects either channel.
Never narrate the routing decision in the spoken reply. The reply is read
aloud verbatim — the row you picked and why is scratch, not speech. Device-observed
leak, 2026-08-24: "A speech-emotion happy cue, fresh decision, audio idle, cooldown
clear — routes to a music suggestion (speak only, unknown user). Sounds like a good
mood — want some upbeat feel-good tunes?" Only the last sentence was the reply;
everything before it was the routing table thought out loud. Start the reply at the
first word the user should hear.
Neutral is filtered upstream at HAL and never reaches this skill in practice; no special case needed here.
Voice cue is weaker than camera cue
Speech emotion ([speech_emotion]) is noisier than facial expression on short utterances — emotion2vec flips between sad / fearful / angry within the same affective state. The hedge (weak voice cue; ...; treat as uncertain, ...) is baked into the message for that reason.
Practical rules:
Don't relax the cooldown. Music suggestions still gate on last_suggestion_age_min ∉ [0, 7) regardless of source. A fresh voice signal does NOT reset the cooldown that a recent camera-driven music suggestion left.
Prefer Comfort/Invite phrasing on voice-only negative reads. When the router falls through to checkin (row #3) and the trigger is [speech_emotion] with bucket=negative, lean toward Comfort/Invite rather than Ask — probing a maybe-misclassified utterance feels worse than acknowledging it.
Cross-modal reinforcement still applies. If recent_signals shows the same mapped_mood from source="camera" in the last ~10 min and now voice fires the same mood, treat it as a confirmation — the Mood skill's decision synthesis already handles this; no extra logic here.
No skip-on-low-confidence. Don't read confidence=... out of the hedge text and pre-filter; HAL already enforced confidence >= SPEECH_EMOTION_CONFIDENCE_THRESHOLD before sending. Anything that reaches this skill is worth logging.
User Emotion Detection next to the 5 skills that share the most tags, products or categories with it. Stars are the repository's; “used in” counts other GitHub owners with a copy.
User Emotion Detection compared with similar skills
Skill
Stars
Used in
Tokens
Auto-check
Licence
Repo updated
User Emotion Detection this skillautonomous-ai/Physical-AI-Operating-System
Discover and use linked third-party services (Gmail, Google Calendar, Google Drive, Notion, Figma, Asana, Linear, GitHub, Ahrefs, Facebook Fan Page and others).
Low-level speaker and microphone hardware control — adjust volume, play test tones, record raw audio.
381 GitHub stars~1k tokensUpdated today
Auto-check passed
Questions about User Emotion Detection
What does User Emotion Detection do?
Maps a detected user emotion — from facial expression (emotion.detected) OR speech (speechemotion.detected) — into a mood signal logged via the Mood skill, then picks one response route (music /…. User Emotion Detection is an agent skill from autonomous-ai/Physical-AI-Operating-System.detected) — into a mood signal logged via the Mood skill, then picks one response route (music / checkin / action).
How do I install User Emotion Detection in Claude Code?
Run `npx skills add autonomous-ai/Physical-AI-Operating-System --skill user-emotion-detection -a claude-code`. Or copy the skill folder (skills/user-emotion-detection in autonomous-ai/Physical-AI-Operating-System) into .claude/skills/user-emotion-detection in your project. Claude Code loads it when a task matches its description.
How do I install User Emotion Detection in Codex?
Run `npx skills add autonomous-ai/Physical-AI-Operating-System --skill user-emotion-detection -a codex`. Or copy the skill folder (skills/user-emotion-detection in autonomous-ai/Physical-AI-Operating-System) into .agents/skills/user-emotion-detection in your project. Codex loads it when a task matches its description.
Can I use User Emotion Detection in Cursor, Gemini CLI or GitHub Copilot?
Cursor, Gemini CLI, GitHub Copilot and OpenCode also load SKILL.md folders. With the skills CLI, run `npx skills add autonomous-ai/Physical-AI-Operating-System --skill user-emotion-detection -a cursor` (or -a gemini-cli, github-copilot or opencode for the others). To copy it by hand, put the folder in .cursor/skills/user-emotion-detection, .gemini/skills/user-emotion-detection, .github/skills/user-emotion-detection and .opencode/skills/user-emotion-detection in your project.
What does User Emotion Detection need to run?
SKILL.md names no scripts, command-line tools or credentials: User Emotion Detection is instructions for the agent only.
Does User Emotion Detection access the network?
SKILL.md contains no URLs. Any network use would come from the scripts or tools the agent runs. This is read from the text; nothing was executed.
Is User Emotion Detection safe to install?
Our automated static check of SKILL.md found no risky patterns, such as piping downloads into a shell, reading credential files or hidden Unicode. It is not a guarantee. Review the folder before installing.
What licence does User Emotion Detection use?
User Emotion Detection is published under the Apache-2.0 licence (the repository's licence). It allows redistribution, so the full SKILL.md is shown on this page.
How many tokens does User Emotion Detection use?
About 3.4k tokens (SKILL.md is roughly 13k characters). Agents keep only the skill's name and description in context until a task matches; then they load SKILL.md in full.
What are the alternatives to User Emotion Detection?
Skills that share tags, products or a category with User Emotion Detection: Customer Journey Map (phuryn/pm-skills, 27k stars), Token Map (nexu-io/open-design, 100k stars), Threat Detection (alirezarezvani/claude-skills, 28k stars) and Maps Geography (asgeirtj/system_prompts_leaks, 69k stars). The comparison table on this page puts their stars, adoption, token cost, safety result and licence side by side.
Who maintains User Emotion Detection?
autonomous-ai (a GitHub organization) maintains it in autonomous-ai/Physical-AI-Operating-System, which has 381 GitHub stars. The repository holds 28 skills in this directory. The repository was last updated on October 9, 2026.