diff --git a/.gitignore b/.gitignore
index 601b429..4a40479 100644
--- a/.gitignore
+++ b/.gitignore
@@ -7,3 +7,4 @@ __pycache__/
.voice_alert
# your personal config, created at setup: never tracked, never touched by updates
ai-visualizer.json
+.worktrees/
diff --git a/docs/superpowers/plans/2026-09-20-cognitive-command-face.md b/docs/superpowers/plans/2026-09-20-cognitive-command-face.md
new file mode 100644
index 0000000..d9a6aca
--- /dev/null
+++ b/docs/superpowers/plans/2026-09-20-cognitive-command-face.md
@@ -0,0 +1,480 @@
+# Cognitive Command Face Implementation Plan
+
+> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
+
+**Goal:** Add an original, always-active cyber-digital Cognitive Command face for Alfred and make it the verified local default.
+
+**Architecture:** Add one self-contained face that consumes the existing `core.js` signal bus and is discovered automatically by `server.py`. Keep rendering, responsive layout, state reactions, and honest diagnostics in that face; leave the server, shared core, and existing faces unchanged.
+
+**Tech Stack:** HTML5 Canvas 2D, vanilla JavaScript, existing `core.js`, Python standard-library `unittest`.
+
+**Spec:** `docs/superpowers/specs/2026-09-20-cognitive-command-face-design.md`
+
+## Global Constraints
+
+- Use a deep blue-black field, cyan mesh, amber operational accents, and red only for alerts.
+- Keep the mesh continuously active without making it visually frantic.
+- Display only real values from `AV`, browser measurements, or the local clock; unsupported values render as `—`.
+- Preserve `core.js`, `server.py`, Neural Core, and every other existing face unchanged.
+- Add no dependency, build step, server endpoint, theme framework, Batman element, humanoid face, or copied franchise graphic.
+- Keep `ai-visualizer.json` untracked; change only its local `face` value after verification passes.
+
+## Review Focus
+
+- No published usage data: omit usage rows instead of inventing percentages; verify in the idle shot with the current default config.
+- Microphone denied or flat: listening still renders and the MIC meter honestly reads zero; verify with browser microphone permission denied.
+- Unsupported memory and bus-health values: display `—`, never `OK`, `READY`, or another inferred status; verify in every fixed-state shot.
+- Narrow or resized viewport: command rails do not cover the mesh or bottom waveform; verify at 720×900 and after resizing from 1920×1080.
+- Alert override: red styling remains readable and does not hide state, clock, or waveform data; verify with `?shot=idle&alert=1`.
+
+---
+
+### Task 1: Add a discoverable face shell and contract check
+
+**Files:**
+
+- Create: `tests/test_cognitive_command_face.py`
+- Create: `faces/cognitive-command/face.json`
+- Create: `faces/cognitive-command/index.html`
+
+**Interfaces:**
+
+- Consumes: `server.list_faces()` and the existing browser global `AV` from `../../core.js`.
+- Produces: gallery face id `cognitive-command`; an HTML page that initializes `AV` with microphone input, ticks it every frame, supports deterministic shots, and toggles fullscreen with `F`.
+
+- [ ] **Step 1: Write the failing discovery and core-contract test**
+
+Create `tests/test_cognitive_command_face.py`:
+
+```python
+import json
+import sys
+import unittest
+from pathlib import Path
+
+
+ROOT = Path(__file__).resolve().parents[1]
+FACE = ROOT / "faces" / "cognitive-command"
+sys.path.insert(0, str(ROOT))
+
+import server # noqa: E402
+
+
+class CognitiveCommandFaceTest(unittest.TestCase):
+ def test_manifest_is_discovered(self):
+ manifest = json.loads((FACE / "face.json").read_text(encoding="utf-8"))
+ self.assertEqual(manifest["title"], "Cognitive Command")
+ self.assertIn("mesh", manifest["tagline"].lower())
+
+ faces = {face["id"]: face for face in server.list_faces()}
+ self.assertIn("cognitive-command", faces)
+ self.assertEqual(faces["cognitive-command"]["title"], "Cognitive Command")
+
+ def test_page_uses_the_shared_face_contract(self):
+ html = (FACE / "index.html").read_text(encoding="utf-8")
+ required = (
+ '',
+ "AV.init({mic:true})",
+ "AV.ready(",
+ "AV.tick(dt)",
+ "AV.shotRun(frame)",
+ "document.documentElement.requestFullscreen()",
+ )
+ for token in required:
+ with self.subTest(token=token):
+ self.assertIn(token, html)
+
+
+if __name__ == "__main__":
+ unittest.main()
+```
+
+- [ ] **Step 2: Run the contract test and confirm it fails**
+
+Run:
+
+```powershell
+python -m unittest discover -s tests -p "test_*.py" -v
+```
+
+Expected: `ERROR` because `faces/cognitive-command/face.json` and `index.html` do not exist.
+
+- [ ] **Step 3: Add the manifest and minimal face shell**
+
+Create `faces/cognitive-command/face.json`:
+
+```json
+{
+ "title": "Cognitive Command",
+ "tagline": "An always-active cyan cognitive mesh surrounded by dense, honest command telemetry."
+}
+```
+
+Create `faces/cognitive-command/index.html` with this complete shell; Task 2 replaces the empty draw body while preserving the contract:
+
+```html
+
+
+
+
+
+Cognitive Command
+
+
+
+
+
+
+
+
+```
+
+- [ ] **Step 4: Run the contract test and confirm it passes**
+
+Run:
+
+```powershell
+python -m unittest discover -s tests -p "test_*.py" -v
+```
+
+Expected: 2 tests pass.
+
+- [ ] **Step 5: Commit the independently discoverable shell**
+
+```powershell
+git add tests/test_cognitive_command_face.py faces/cognitive-command/face.json faces/cognitive-command/index.html
+git commit -m "feat: add Cognitive Command face shell"
+```
+
+### Task 2: Build and verify the living command mesh
+
+**Files:**
+
+- Modify: `tests/test_cognitive_command_face.py`
+- Modify: `faces/cognitive-command/index.html`
+- Modify locally, never stage: `ai-visualizer.json`
+
+**Interfaces:**
+
+- Consumes: `AV.state`, `AV.env`, `AV.samples`, `AV.micLevel`, `AV.alert`, `AV.label`, `AV.badge`, and `AV.util.usageRows()`.
+- Produces: `buildMesh()`, `updateSignals(dt,state)`, `drawBackground(t)`, `drawMesh(t)`, `drawChrome(state)`, `drawWaveforms(state)`, `drawAlertFrame()`, `resize()`, and `frame(dt)` inside the self-contained page.
+
+- [ ] **Step 1: Extend the contract test for renderer and telemetry boundaries**
+
+Add this method to `CognitiveCommandFaceTest`:
+
+```python
+ def test_page_contains_renderer_and_honest_telemetry(self):
+ html = (FACE / "index.html").read_text(encoding="utf-8")
+ required = (
+ "function mulberry32(",
+ "function buildMesh(",
+ "function updateSignals(",
+ "function drawBackground(",
+ "function drawMesh(",
+ "function drawChrome(",
+ "function drawWaveforms(",
+ "function drawAlertFrame(",
+ "AV.util.usageRows()",
+ '["MEMORY","—"]',
+ '["BUS HEALTH","—"]',
+ 'Q.get("alert")==="1"',
+ )
+ for token in required:
+ with self.subTest(token=token):
+ self.assertIn(token, html)
+
+ forbidden = ('["MEMORY","OK"]', '["BUS HEALTH","OK"]')
+ for token in forbidden:
+ with self.subTest(token=token):
+ self.assertNotIn(token, html)
+```
+
+- [ ] **Step 2: Run the expanded test and confirm it fails**
+
+Run:
+
+```powershell
+python -m unittest discover -s tests -p "test_*.py" -v
+```
+
+Expected: the new renderer test fails on `function mulberry32(`.
+
+- [ ] **Step 3: Implement the deterministic mesh and state model**
+
+Replace the shell script body after `AV.ready(a=>...)` with these exact contracts and values:
+
+```javascript
+const U=AV.util;
+const CYAN=[80,205,255],PALE=[190,238,255],AMBER=[239,182,94],RED=[255,58,68];
+const PROFILE={
+ idle:{traffic:1.8,drift:.22,scan:.18,energy:.34},
+ listening:{traffic:4.0,drift:.16,scan:.32,energy:.52},
+ thinking:{traffic:12.0,drift:.58,scan:1.0,energy:.92},
+ speaking:{traffic:8.0,drift:.40,scan:.62,energy:.70},
+};
+const FORCE_ALERT=Q.get("alert")==="1";
+function mulberry32(a){return function(){a|=0;a=a+0x6D2B79F5|0;let t=Math.imul(a^a>>>15,1|a);t=t+Math.imul(t^t>>>7,61|t)^t;return((t^t>>>14)>>>0)/4294967296}}
+const TAU=Math.PI*2;
+let rng=mulberry32(41),mesh={nodes:[],edges:[],pulses:[]},spawnCarry=0;
+let listenMix=0,thinkMix=0,speakMix=0,stateAge=0,previousState="idle";
+function buildMesh(){
+ rng=mulberry32(41);
+ const nodes=Array.from({length:96},(_,i)=>{
+ const a=rng()*TAU,r=Math.sqrt(rng());
+ return{x:Math.cos(a)*r,y:Math.sin(a)*r*.68,z:(rng()-.5)*.9,
+ phase:rng()*TAU,size:1+rng()*1.6,band:i%4};
+ });
+ const edges=[],seen=new Set();
+ // ponytail: O(n²) runs only on resize; add a spatial index only if resize profiling needs it.
+ nodes.forEach((n,i)=>{
+ nodes.map((m,j)=>({j,d:j===i?Infinity:Math.hypot(n.x-m.x,n.y-m.y,n.z-m.z)}))
+ .sort((a,b)=>a.d-b.d).slice(0,3).forEach(({j})=>{
+ const a=Math.min(i,j),b=Math.max(i,j),key=`${a}:${b}`;
+ if(!seen.has(key)){seen.add(key);edges.push({a,b})}
+ });
+ });
+ mesh={nodes,edges,pulses:[]};spawnCarry=0;
+}
+function pulseDirection(edge,state){
+ const a=mesh.nodes[edge.a],b=mesh.nodes[edge.b];
+ const ra=Math.hypot(a.x,a.y,a.z),rb=Math.hypot(b.x,b.y,b.z);
+ if(state==="listening")return ra>rb?1:-1;
+ if(state==="speaking")return ra=1&&mesh.pulses.length<72){
+ spawnCarry--;
+ const edge=rng()*mesh.edges.length|0;
+ mesh.pulses.push({edge,t:0,speed:.30+rng()*.32,
+ dir:pulseDirection(mesh.edges[edge],state)});
+ }
+ for(const pulse of mesh.pulses)pulse.t+=pulse.speed*dt/1000;
+ mesh.pulses=mesh.pulses.filter(pulse=>pulse.t<1);
+}
+function easeMix(value,target,dt){return value+(target-value)*(1-Math.exp(-dt/280))}
+```
+
+Call `buildMesh()` from `resize()`. In `frame(dt)`, reset `stateAge` when `AV.state` changes, then update it and the three mixes with `easeMix`. This preserves one stable mesh identity while state changes crossfade rather than cut.
+
+- [ ] **Step 4: Implement the full command-centre rendering pass**
+
+Add these rendering helpers and keep their data sources unchanged:
+
+```javascript
+let field=document.createElement("canvas"),fg=field.getContext("2d");
+let micHistory=Array(72).fill(0),now=0,fps=0,fpsCount=0,fpsAt=0;
+function rgba(c,a){return`rgba(${c[0]},${c[1]},${c[2]},${a})`}
+function projectNode(n,t){
+ const yaw=Math.sin(t*.18)*.22+thinkMix*.12,cy=Math.cos(yaw),sy=Math.sin(yaw);
+ const x=n.x*cy+n.z*sy,z=-n.x*sy+n.z*cy;
+ const perspective=2.7/(2.7+z),scale=Math.min(W,H)*.39;
+ return{x:W/2+x*scale*perspective,y:H*.49+n.y*scale*perspective,
+ z,perspective};
+}
+function drawBackground(t){
+ const alert=FORCE_ALERT||AV.alert,col=alert?RED:CYAN;
+ const g=ctx.createRadialGradient(W/2,H*.48,0,W/2,H*.48,Math.max(W,H)*.72);
+ g.addColorStop(0,alert?"#21060a":"#071d2b");g.addColorStop(.5,"#020a11");g.addColorStop(1,"#010306");
+ ctx.fillStyle=g;ctx.fillRect(0,0,W,H);
+ ctx.strokeStyle=rgba(col,.08);ctx.lineWidth=1;
+ for(let i=0;i<12;i++){
+ const y=H*.58+i*i*H*.0036;ctx.beginPath();ctx.moveTo(0,y);ctx.lineTo(W,y);ctx.stroke();
+ }
+ for(let i=-10;i<=10;i++){
+ ctx.beginPath();ctx.moveTo(W/2,H*.56);ctx.lineTo(W/2+i*W*.09,H);ctx.stroke();
+ }
+ const scan=(t*40*(.2+PROFILE[AV.state].scan))%(W+240)-120;
+ ctx.fillStyle=rgba(col,.035);ctx.fillRect(scan,0,80,H);
+}
+function drawMesh(t){
+ fg.clearRect(0,0,W,H);
+ const alert=FORCE_ALERT||AV.alert,col=alert?RED:CYAN;
+ const projected=mesh.nodes.map(node=>projectNode(node,t));
+ fg.globalCompositeOperation="lighter";fg.lineWidth=1;
+ for(const edge of mesh.edges){
+ const a=projected[edge.a],b=projected[edge.b];
+ fg.strokeStyle=rgba(col,.10+.16*thinkMix);
+ fg.beginPath();fg.moveTo(a.x,a.y);fg.lineTo(b.x,b.y);fg.stroke();
+ }
+ for(let i=0;i0?pulse.t:1-pulse.t,x=a.x+(b.x-a.x)*q,y=a.y+(b.y-a.y)*q;
+ fg.fillStyle=rgba(alert?RED:(AV.state==="listening"?AMBER:PALE),1);
+ fg.beginPath();fg.arc(x,y,2.5+2*thinkMix,0,TAU);fg.fill();
+ }
+ fg.globalCompositeOperation="source-over";
+ U.bloomBlit(ctx,field,W,H);
+}
+function drawPanel(x,y,title,rows,right=false){
+ ctx.textAlign=right?"right":"left";ctx.textBaseline="top";
+ ctx.font="11px Consolas,monospace";ctx.fillStyle=rgba(PALE,.9);ctx.fillText(title,x,y);
+ ctx.strokeStyle=rgba(CYAN,.3);ctx.beginPath();ctx.moveTo(right?x-160:x,y+18);ctx.lineTo(right?x:x+160,y+18);ctx.stroke();
+ rows.forEach((row,i)=>{
+ const yy=y+28+i*18;ctx.fillStyle=rgba(CYAN,.6);ctx.fillText(`${row[0]} ${row[1]}`,x,yy);
+ });
+ ctx.textAlign="left";
+}
+function drawChrome(state){
+ const pct=value=>`${Math.round(Math.max(0,Math.min(1,value))*100)}%`;
+ const energy=AV.samples.reduce((sum,value)=>sum+Math.abs(value),0)/AV.samples.length;
+ let left=[["STATE",state.toUpperCase()],["STATE AGE",`${(stateAge/1000).toFixed(1)}s`],
+ ["MIC LEVEL",pct(AV.micLevel)],["VOICE ENV",pct(AV.env)],["WAVE ENERGY",pct(energy)],["FPS",String(fps)]];
+ let right=[["LOCAL TIME",new Date().toLocaleTimeString([], {hour12:false})],
+ ["VIEWPORT",`${W}×${H}`],["MEMORY","—"],["BUS HEALTH","—"]];
+ for(const row of AV.util.usageRows())right.push([row.label,row.text]);
+ if(W<1000){left=left.slice(0,4);right=right.slice(0,4)}
+ ctx.font="bold 15px Consolas,monospace";ctx.fillStyle=rgba(PALE,.95);
+ ctx.fillText(AV.label,24,22);ctx.textAlign="center";ctx.fillText(state.toUpperCase(),W/2,22);ctx.textAlign="left";
+ if(W>=760){drawPanel(24,72,"INPUT / COGNITION",left);drawPanel(W-24,72,"SYSTEM / SESSION",right,true)}
+}
+function drawWaveforms(state){
+ micHistory.push(AV.micLevel);micHistory=micHistory.slice(-72);
+ const draw=(values,y,h,col)=>{
+ ctx.strokeStyle=rgba(col,.9);ctx.lineWidth=1.5;ctx.beginPath();
+ values.forEach((value,i)=>{const x=24+i*(W-48)/(values.length-1),yy=y-value*h;(i?ctx.lineTo(x,yy):ctx.moveTo(x,yy))});ctx.stroke();
+ };
+ draw(micHistory,H-34,22,state==="listening"?AMBER:CYAN);
+ draw(Array.from(AV.samples),H-68,26,state==="speaking"?PALE:CYAN);
+}
+function drawAlertFrame(){
+ const a=.45+.35*Math.sin(now/180)**2;ctx.fillStyle=rgba(RED,a);
+ ctx.fillRect(0,0,W,6);ctx.fillRect(0,H-6,W,6);ctx.fillRect(0,0,6,H);ctx.fillRect(W-6,0,6,H);
+ ctx.textAlign="center";ctx.font="bold 14px Consolas,monospace";ctx.fillText("ALERT",W/2,48);ctx.textAlign="left";
+}
+```
+
+Keep the whole page in one canvas. In `resize()`, set `field.width=W` and `field.height=H` after applying `DPR=Math.min(2,devicePixelRatio||1)` to the visible canvas, then call `buildMesh()`. In `frame(dt)`, call functions in this order: `AV.tick`, state-age/mix easing, `updateSignals`, `drawBackground`, `drawMesh`, `drawChrome`, `drawWaveforms`, and `drawAlertFrame` when `FORCE_ALERT||AV.alert` is true. Update `fps` once per second from `fpsCount` and `fpsAt`.
+
+For widths under 1000 px, reduce each side rail to four rows and narrow it to 150 px. For widths under 760 px, keep only the title/state header, central mesh, bottom waveforms, and alert treatment.
+
+- [ ] **Step 5: Run the automated checks**
+
+Run:
+
+```powershell
+python -m unittest discover -s tests -p "test_*.py" -v
+git diff --check
+```
+
+Expected: 3 tests pass and `git diff --check` prints nothing.
+
+- [ ] **Step 6: Verify the fixed states and review-focus cases in a browser**
+
+Start the local server in a persistent terminal:
+
+```powershell
+python server.py --port 8791 --no-open
+```
+
+Open each URL, wait until the tab title becomes `ready`, and inspect at 1920×1080:
+
+```text
+http://127.0.0.1:8791/faces/cognitive-command/?shot=idle&t=4000
+http://127.0.0.1:8791/faces/cognitive-command/?shot=listening&t=4000
+http://127.0.0.1:8791/faces/cognitive-command/?shot=thinking&t=4000
+http://127.0.0.1:8791/faces/cognitive-command/?shot=speaking&t=4000
+http://127.0.0.1:8791/faces/cognitive-command/?shot=idle&t=4000&alert=1
+```
+
+Confirm: state reactions are distinct; idle remains active; unsupported MEMORY and BUS HEALTH show `—`; no usage row appears when no usage is published; alert data remains readable.
+
+Repeat the listening shot at 720×900 with microphone permission denied. Confirm the mesh still reacts to state, MIC reads zero, and the rails do not overlap the mesh or waveforms. Resize the live demo from 1920×1080 to 720×900 and back to confirm buffers rebuild without stale pixels:
+
+```text
+http://127.0.0.1:8791/faces/cognitive-command/?demo=1
+```
+
+Watch one complete demo cycle and confirm all four state transitions. Then verify the real alert signal only when no alert is already present:
+
+```powershell
+$alertSignal = 'E:\Alfred\backtalk\.voice_alert'
+if (Test-Path -LiteralPath $alertSignal) { throw 'Existing alert is active; do not replace it.' }
+try {
+ Set-Content -LiteralPath $alertSignal -Value 'visual verification'
+ Read-Host 'Open http://127.0.0.1:8791/faces/cognitive-command/ and confirm the red alert treatment, then press Enter'
+}
+finally {
+ Remove-Item -LiteralPath $alertSignal -ErrorAction SilentlyContinue
+}
+```
+
+Confirm the live page enters and leaves the red alert treatment. The `finally` block removes only the signal this step created.
+
+- [ ] **Step 7: Make Cognitive Command the local default only after verification**
+
+Change exactly this ignored local-config line in `ai-visualizer.json`:
+
+```diff
+- "face": "neural",
++ "face": "cognitive-command",
+```
+
+Verify the config and gallery discovery:
+
+```powershell
+python -c "import json,urllib.request; c=json.load(open('ai-visualizer.json')); assert c['face']=='cognitive-command'; d=json.load(urllib.request.urlopen('http://127.0.0.1:8791/config')); assert any(f['id']=='cognitive-command' for f in d['faces']); print('config and gallery ok')"
+```
+
+Expected: `config and gallery ok`.
+
+Start Alfred through `E:\Alfred\Talk to Alfred.bat`, open the Cognitive Command face without `shot` or `demo` parameters, and complete one short spoken turn. Confirm the real bus drives listening → thinking → speaking, the microphone trace moves during listening, and the output trace follows Alfred's spoken response. If this live check fails, change the local `face` value back to `neural` before stopping and report the observed failure instead of claiming completion.
+
+- [ ] **Step 8: Prove existing faces and shared plumbing were not modified**
+
+Run:
+
+```powershell
+git diff --exit-code HEAD -- core.js server.py faces/board faces/radial faces/rain faces/neural
+git status --short
+```
+
+Expected: the first command prints nothing; status shows only `faces/cognitive-command/` and `tests/test_cognitive_command_face.py`. The ignored `ai-visualizer.json` does not appear.
+
+- [ ] **Step 9: Commit the verified face**
+
+```powershell
+git add faces/cognitive-command/index.html tests/test_cognitive_command_face.py
+git commit -m "feat: add Alfred cognitive command face"
+```
diff --git a/docs/superpowers/specs/2026-09-20-cognitive-command-face-design.md b/docs/superpowers/specs/2026-09-20-cognitive-command-face-design.md
new file mode 100644
index 0000000..d71a3d3
--- /dev/null
+++ b/docs/superpowers/specs/2026-09-20-cognitive-command-face-design.md
@@ -0,0 +1,75 @@
+# Cognitive Command Face Design
+
+## Objective
+
+Give Alfred an original cyber-digital command-centre face built around a living cognitive mesh. The face must feel continuously active, expose dense real diagnostics, and react clearly to Alfred's voice states without copying the visual identity of JARVIS, Batman, or another franchise.
+
+## User experience
+
+The full-screen view uses a deep blue-black field, a central cyan cognitive mesh, restrained amber operational highlights, and red only for alerts. Motion continues at idle through low-amplitude node drift, signal traffic, and scanning planes. The interface remains readable rather than becoming visually frantic.
+
+The layout has four zones:
+
+- A large central three-dimensional mesh with traveling signals and depth haze.
+- A left command rail for input, cognition, memory, and local-runtime telemetry.
+- A right command rail for subsystem status, plan usage, bus health, clock, and state timing.
+- A bottom rail for microphone and voice waveforms plus the current session state.
+
+## State behaviour
+
+| State | Visual response |
+|---|---|
+| Idle | Continuous low-rate traffic, slow scans, and stable diagnostics. |
+| Listening | Microphone energy pulls signals inward; the input rail turns amber. |
+| Thinking | Routing traffic accelerates; active nodes and cognition or memory panels brighten. |
+| Speaking | Energy propagates outward; the bottom waveform follows the real audio envelope. |
+| Alert | The palette shifts to red and the perimeter pulse strengthens without hiding diagnostics. |
+
+Transitions are eased rather than cut. Missing or disconnected values display `—` or `OFFLINE`; the face never invents telemetry.
+
+## Technical design
+
+Add a standalone face at `faces/cognitive-command/` containing:
+
+- `index.html` for the canvas renderer, layout, animation, and state reactions.
+- `face.json` for gallery discovery, title, and description.
+
+The face uses the existing `core.js` contract: `AV.state`, `AV.env`, `AV.samples`, `AV.micLevel`, `AV.alert`, identity labels, rate-limit rows, and shared utilities. No dependency, build step, new server endpoint, or change to `core.js` is required.
+
+The existing Neural Core and other upstream faces remain unchanged. After verification, the untracked local `ai-visualizer.json` default changes from `neural` to `cognitive-command`. Reverting that one value restores the previous default.
+
+## Rendering approach
+
+Use one full-window canvas and deterministic seeded geometry so the mesh has a stable identity between launches. Build the mesh once on startup, then update only positions, signal progress, eased state weights, and telemetry each frame. Draw luminous elements to an off-screen field and apply the existing bloom utility before compositing crisp labels and panels.
+
+Use native Canvas 2D, browser APIs, and existing utilities only. The design should degrade cleanly in smaller windows by reducing secondary labels before shrinking the central mesh.
+
+## Boundaries
+
+- No Batman, bat emblem, yellow oval, cave styling, or copied franchise graphics.
+- No humanoid face.
+- No fabricated CPU, memory, security, or connectivity values.
+- No change to voice, approval, memory-vault, server, or signal-bus behaviour.
+- No new dependencies or reusable theme framework.
+
+## Verification
+
+Verify:
+
+1. `?shot=idle`, `listening`, `thinking`, and `speaking` rendering.
+2. The complete `?demo=1` transition cycle.
+3. Live microphone and voice-waveform reactions through the existing bus.
+4. Alert rendering through the existing `.voice_alert` signal.
+5. Missing-bus behaviour and honest offline indicators.
+6. Fullscreen keyboard behaviour.
+7. Layout at 1920×1080 and a smaller window.
+8. Gallery discovery through `face.json`.
+9. The previous Neural Core remains selectable and unchanged.
+
+## Acceptance criteria
+
+- Alfred defaults to the new Cognitive Command face locally.
+- The central mesh is visibly alive at idle and clearly differentiates all live states.
+- Dense diagnostics remain legible and show only available data.
+- No new dependency, server change, or modification to an existing face is introduced.
+- Relevant static, demo, and live checks pass, and the final diff contains no private configuration or generated mockups.
diff --git a/faces/cognitive-command/face.json b/faces/cognitive-command/face.json
new file mode 100644
index 0000000..e301c0c
--- /dev/null
+++ b/faces/cognitive-command/face.json
@@ -0,0 +1,4 @@
+{
+ "title": "Cognitive Command",
+ "tagline": "An always-active cyan cognitive mesh surrounded by dense, honest command telemetry."
+}
diff --git a/faces/cognitive-command/index.html b/faces/cognitive-command/index.html
new file mode 100644
index 0000000..360d84b
--- /dev/null
+++ b/faces/cognitive-command/index.html
@@ -0,0 +1,295 @@
+
+
+
+
+
+
+Cognitive Command
+
+
+
+
+
+
+
+
diff --git a/tests/test_cognitive_command_face.py b/tests/test_cognitive_command_face.py
new file mode 100644
index 0000000..bae08de
--- /dev/null
+++ b/tests/test_cognitive_command_face.py
@@ -0,0 +1,88 @@
+import json
+import sys
+import threading
+import unittest
+import urllib.request
+from html.parser import HTMLParser
+from http.server import ThreadingHTTPServer
+from pathlib import Path
+
+
+ROOT = Path(__file__).resolve().parents[1]
+sys.path.insert(0, str(ROOT))
+
+import server # noqa: E402
+
+
+class FacePageParser(HTMLParser):
+ def __init__(self):
+ super().__init__()
+ self.canvas = None
+ self.scripts = []
+ self.in_title = False
+ self.title = ""
+
+ def handle_starttag(self, tag, attrs):
+ attrs = dict(attrs)
+ if tag == "canvas" and attrs.get("id") == "stage":
+ self.canvas = attrs
+ elif tag == "script" and "src" in attrs:
+ self.scripts.append(attrs["src"])
+ elif tag == "title":
+ self.in_title = True
+
+ def handle_endtag(self, tag):
+ if tag == "title":
+ self.in_title = False
+
+ def handle_data(self, data):
+ if self.in_title:
+ self.title += data
+
+
+class CognitiveCommandFaceTest(unittest.TestCase):
+ @classmethod
+ def setUpClass(cls):
+ cls.httpd = ThreadingHTTPServer(("127.0.0.1", 0), server.Handler)
+ cls.thread = threading.Thread(target=cls.httpd.serve_forever, daemon=True)
+ cls.thread.start()
+ cls.base_url = f"http://127.0.0.1:{cls.httpd.server_port}"
+
+ @classmethod
+ def tearDownClass(cls):
+ cls.httpd.shutdown()
+ cls.httpd.server_close()
+ cls.thread.join(timeout=2)
+
+ def get_json(self, path):
+ with urllib.request.urlopen(self.base_url + path, timeout=2) as response:
+ self.assertEqual(response.status, 200)
+ return json.load(response)
+
+ def test_face_is_discovered_and_served_with_browser_contract(self):
+ config = self.get_json("/config")
+ faces = {face["id"]: face for face in config["faces"]}
+ self.assertIn("cognitive-command", faces)
+ self.assertEqual(faces["cognitive-command"]["title"], "Cognitive Command")
+ self.assertIn("mesh", faces["cognitive-command"]["tagline"].lower())
+
+ with urllib.request.urlopen(
+ self.base_url + "/faces/cognitive-command/index.html", timeout=2
+ ) as response:
+ self.assertEqual(response.status, 200)
+ self.assertEqual(response.headers.get_content_type(), "text/html")
+ html = response.read().decode("utf-8")
+
+ parser = FacePageParser()
+ parser.feed(html)
+ self.assertEqual(parser.title.strip(), "Cognitive Command")
+ self.assertIsNotNone(parser.canvas)
+ self.assertEqual(parser.canvas.get("role"), "img")
+ self.assertEqual(
+ parser.canvas.get("aria-label"), "Alfred Cognitive Command interface"
+ )
+ self.assertIn("../../core.js", parser.scripts)
+
+
+if __name__ == "__main__":
+ unittest.main()