app
Codex
Public Made by Adomby adom
Codex in Adom Hydrogen: ecosystem setup, dock dashboard and live engineering demos.
← Commit history
0.1.15: the prompt panel prefers Codex in Hydrogen's AI picker (prefer, not a forced type), needs Hydrogen 1.0.232+ (background sends find their tab again)
3 files changed
+21−61
adom_codex.py+3−2@@ -26,8 +26,9 @@ class Handler(SimpleHTTPRequestHandler): if self.command=='POST' and self.path=='/codex/ai-threads/run-prompt': try: status=json.load(urllib.request.urlopen(base.rstrip('/')+'/updater/status',timeout=10))- if status.get('updater',{}).get('current_version')=='1.0.230':return self.json({'ok':False,'error':'Codex delivery is not reliable in Hydrogen 1.0.230. Copy this prompt and paste it into a verified Codex conversation; select Astra there. No prompt was sent.'},409)- payload=json.loads(data);payload['type']='codex';payload['background']=True;data=json.dumps(payload).encode()+ cur=str(status.get('updater',{}).get('current_version') or '0');ver=tuple(int(x) for x in cur.split('.')[:3] if x.isdigit())+ if ver<(1,0,232):return self.json({'ok':False,'error':'This needs Hydrogen 1.0.232 or later (the AI picker default and reliable background sends); you are on '+cur+'. Update Hydrogen, or copy this prompt into a Codex tab yourself.'},409)+ payload=json.loads(data);payload['prefer']='codex';payload.pop('type',None);payload['background']=True;data=json.dumps(payload).encode() except (ValueError,TypeError,AttributeError):return self.json({'error':'Valid JSON object required'},400) except (OSError,urllib.error.URLError):return self.json({'error':'Cannot verify Hydrogen version; no prompt was sent.'},503) req=urllib.request.Request(base.rstrip('/')+upstream,data=data,method=self.command,headers={'Content-Type':'application/json'})
dashboard/index.html+5−2@@ -2,8 +2,11 @@ :root{color-scheme:dark;--bg:#0d1117;--card:#161b22;--text:#e6edf3;--muted:#8b949e;--line:#30363d;--teal:#00b8b1}*{box-sizing:border-box}body{margin:0;background:var(--bg);color:var(--text);font:15px 'Familjen Grotesk',system-ui,sans-serif}header{height:44px;border-bottom:1px solid var(--line);display:flex;align-items:center;gap:8px;padding:0 16px}header img{width:18px;height:18px}header strong{font-size:15px}header span{color:var(--muted);font-size:13px}.spacer{flex:1}button,a{touch-action:manipulation}button{background:var(--card);color:var(--text);border:1px solid var(--line);border-radius:6px;padding:8px 12px;cursor:pointer}button:hover,button:focus-visible{border-color:var(--teal)}main{margin:auto;padding:16px}h1{font-size:30px;margin:0 0 8px}h2{font-size:19px}p{line-height:1.6;color:var(--muted)}a{color:var(--teal)}.pills{display:flex;gap:8px;flex-wrap:wrap;margin:16px 0}.pill{border:1px solid var(--line);border-radius:20px;padding:6px 12px;font-size:12px}.grid{display:grid;grid-template-columns:repeat(2,1fr);gap:16px}.card{padding:22px;background:var(--card);border:1px solid var(--line);border-radius:12px}.card button{margin-right:8px}video{width:100%;max-height:70vh;background:#000}dialog{width:min(1100px,95vw);background:var(--card);color:var(--text);border:1px solid var(--line);border-radius:12px}dialog::backdrop{background:#0008}pre{white-space:pre-wrap;word-break:break-word}.close{float:right}#toast{position:fixed;bottom:20px;left:50%;transform:translateX(-50%);background:var(--card);padding:12px;border:1px solid var(--teal);border-radius:8px;display:none}@media(max-width:720px){.grid{grid-template-columns:1fr}header span{display:none}main{padding:16px}} </style><header><img src="/dashboard/icon.svg" alt=""><strong title="Codex integration">Codex</strong><span>Engineering in Hydrogen</span><div class="spacer"></div><span id="machine">Container</span><button id="help" title="Show or hide starter prompts" aria-label="Starter prompts">?</button><button id="settings" title="Integration details" aria-label="Integration details"><svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8"><path d="m10 2 4 0 1 3 3 2 3 0 1 4-2 2-1 3 1 3-4 2-2-2-3-1-3 1-2-4 2-2 1-3-1-3 4-2z"/><circle cx="12" cy="12" r="3"/></svg></button></header><main><div id="newbie"></div><div class="pills" id="status"><span class="pill">Checking local integration</span></div><h1>Turn a prompt into working engineering.</h1><p>Orient Codex in your Adom workspace, then drive real tools through Adom Bridge.</p><div class="grid"><section class="card"><h2>Astra routes and checks a real Fusion board</h2><p>Watch Astra-calculated 45-degree routes, native vias and connected thermal pours appear in Fusion. Then reproduce the workflow on your desktop with the packaged skills.</p><button data-demo="https://wiki.adom.inc/api/pages/adom/codex/files/videos/fusion/10-bq25792-thermal-45-narrated.mp4">Watch the latest video · 3:43</button><a href="https://wiki.adom.inc/adom/codex/files/docs/REPRODUCE-FUSION.md" target="_blank">Reproduce this with Astra</a><p>Copy the first prompt into Codex and select Astra. Send to AI is paused on Hydrogen 1.0.230 because its provider routing failed our desktop test.</p></section><section class="card"><h2>Workspace setup</h2><p>The package installs an ecosystem entry point, a focused skill and a context command. Your existing instructions and credentials stay yours.</p><button id="inspect">Inspect this workspace</button><a href="https://wiki.adom.inc/adom/codex/files/docs/BOOTSTRAP.md" target="_blank">Setup guide</a></section><section class="card"><h2>Astra routes live in KiCad</h2><p>Watch traces, layer-changing vias and branched nets appear in the real editor. The captions explain the calculation and the measured results.</p><button data-demo="01-astra-live-routing-3x.mp4">6-net demo · 23 sec</button><button data-demo="02-astra-crossbar-24-3x.mp4">24-net demo · 31 sec</button></section><section class="card"><h2>Real-board comparisons</h2><p>Watch a public Adom board go from the human reference to zero traces and independently calculated routing, with narrated explanations and measured KiCad results.</p><button data-demo="04-public-adom-solenoid-full-routing-narrated.mp4">Public board · narrated · 82 sec</button><a href="https://wiki.adom.inc/adom/codex/files/docs/ASTRA-KICAD.md" target="_blank">Read the engineering log</a></section><section class="card"><h2>Codex Desktop</h2><p>Planned: verified desktop installation and a Bridge connection between Hydrogen and Codex Desktop. Desktop controls are not installed by this version.</p><a href="https://wiki.adom.inc/adom/codex/files/docs/DESKTOP-BRIDGE.md" target="_blank">Integration roadmap</a></section></div></main><dialog id="player"><button class="close" id="close-video" title="Close video">Close</button><h2>Astra engineering demonstrations</h2><video id="video" controls playsinline></video></dialog><dialog id="details"><button class="close" id="close-details">Close</button><h2>Local integration</h2><pre id="context"></pre></dialog><div id="toast" role="status"></div><script src="/dashboard/vendor/newbie-panel.js"></script><script> const $=s=>document.querySelector(s);function toast(s){$('#toast').textContent=s;$('#toast').style.display='block';setTimeout(()=>$('#toast').style.display='none',4000)}-function play(file){document.querySelector('.anp-video')?.pause();$('#video').src=file.startsWith('https://')?file:'/videos/'+file;$('#player').showModal();$('#video').play().catch(()=>toast('Press Play to start the video.'))}-const panel=AdomNewbiePanel.mount({mount:'#newbie',apiBase:'/codex',app:'codex',appName:'Codex',slug:'codex',toggleButton:'#help',demo:{label:'Play the Fusion demo',meta:'3:43 · narrated · Astra in Fusion',video:{src:'https://wiki.adom.inc/api/pages/adom/codex/files/videos/fusion/10-bq25792-thermal-45-narrated.mp4',poster:'/dashboard/fusion-demo-poster.jpg',title:'Astra routes a Fusion board with connected thermal copper'}},phrases:["Codex Astra, reproduce this Fusion demo",'Codex, inspect this workspace','Codex, review my PCB thermal paths']});+function play(file){document.querySelector('#fusion-demo')?.pause();$('#video').src=file.startsWith('https://')?file:'/videos/'+file;$('#player').showModal();$('#video').play().catch(()=>toast('Press Play to start the video.'))}+const panel=AdomNewbiePanel.mount({mount:'#newbie',apiBase:'/codex',app:'codex',ai:'codex',appName:'Codex',slug:'codex',toggleButton:'#help',onToggle:open=>{if(!open)document.querySelector('#fusion-demo')?.pause()},demo:{label:'Watch the routing demo',meta:'Fusion thermal routing, 3 min 43 sec',onPlay:()=>document.querySelector('#fusion-demo').play().catch(()=>toast('Press Play to start the video.'))},phrases:["Codex Astra, reproduce this Fusion demo",'Codex, inspect this workspace','Codex, review my PCB thermal paths']});+const demoColumn=document.querySelector('#newbie .anp-left');+const inlineDemo=document.createElement('video');inlineDemo.id='fusion-demo';inlineDemo.controls=true;inlineDemo.playsInline=true;inlineDemo.preload='none';inlineDemo.poster='/dashboard/fusion-demo-poster.jpg';inlineDemo.src='https://wiki.adom.inc/api/pages/adom/codex/files/videos/fusion/10-bq25792-thermal-45-narrated.mp4';inlineDemo.setAttribute('aria-label','Astra Fusion thermal routing video');inlineDemo.style.cssText='display:block;width:100%;margin-top:12px;border-radius:8px;aspect-ratio:16/9';demoColumn.appendChild(inlineDemo);+const demoCaption=document.createElement('p');demoCaption.textContent='Astra in Fusion · 3:43 · narrated';demoCaption.style.cssText='font-size:12px;margin:6px 0 0';demoColumn.appendChild(demoCaption); async function inspect(){try{const r=await fetch('/api/status');if(!r.ok)throw Error('Context unavailable');const s=await r.json();$('#context').textContent=JSON.stringify(s,null,2);$('#details').showModal()}catch(e){toast(e.message)}} $('#inspect').onclick=inspect;$('#settings').onclick=inspect;$('#close-details').onclick=()=>$('#details').close();$('#close-video').onclick=()=>$('#player').close();$('#player').addEventListener('close',()=>$('#video').pause());document.querySelectorAll('[data-demo]').forEach(b=>b.onclick=()=>play(b.dataset.demo)); function status(s){$('#machine').textContent=s.container.hostname;$('#status').replaceChildren(...['Entry point: '+(s.instructionsInstalled?'installed':'not installed'),'Bridge CLI: '+(s.tools['adom-bridge']?'available':'missing'),'Host target: select in Bridge'].map(t=>{let e=document.createElement('span');e.className='pill';e.textContent=t;return e}))}
dashboard/vendor/newbie-panel.js+13−57@@ -78,19 +78,6 @@ .anp-left{flex-direction:row; align-items:center; gap:12px;} } -/* A video is content, not an icon in the legacy 220px demo-button column.- * Opt-in only: existing button-only panels keep their original layout. */-.anp.anp--video{grid-template-columns:minmax(0,720px) minmax(360px,1fr);align-items:start;}-.anp--video .anp-left{min-width:0;display:flex;flex-direction:column;align-items:stretch;gap:12px;}-.anp-video{display:block;width:100%;height:auto;max-height:none;aspect-ratio:16/9;object-fit:contain;background:#080c11;border-radius:8px;}-.anp-video-toolbar{display:flex;flex-wrap:wrap;align-items:center;gap:10px 16px;}-.anp--video .anp-phrase span{white-space:normal;overflow:visible;text-overflow:clip;overflow-wrap:anywhere;padding:10px 8px 10px 0;}-.anp--video .anp-tbl{max-width:none;}-.anp--video .anp-right{align-self:center;}-@container anp (max-width:1099px){- .anp.anp--video{grid-template-areas:"head" "left" "right";grid-template-columns:minmax(0,1fr);}-}- .anp-toasts{position:fixed; left:50%; bottom:22px; transform:translateX(-50%); z-index:99999; display:flex; flex-direction:column-reverse; gap:8px; pointer-events:none;} .anp-toast{pointer-events:auto; display:flex; align-items:center; gap:10px; max-width:min(92vw,520px);@@ -268,7 +255,10 @@ headers: { 'content-type': 'application/json' }, body: JSON.stringify({ "new": true, prompt: phrase, submit: true,- name: appName + ' - say it', tags: ['dock:' + slug]+ name: appName + ' - say it', tags: ['dock:' + slug],+ /* cfg.ai = the AI this dashboard belongs to. Hydrogen 1.0.231+ shows the picker with+ * it as the countdown default (John 2026-09-06); older Hydrogens ignore the field. */+ prefer: cfg.ai || undefined }) }).then(function (r) { return r.json().then(function (j) { return { status: r.status, j: j }; }); }) .then(function (res) {@@ -344,9 +334,7 @@ var key = 'anp:' + slug + ':open'; var wrap = el('div', 'anp-wrap');- var videoCfg = cfg.demo && cfg.demo.video;- var video = null;- var panel = el('section', 'anp' + (videoCfg && videoCfg.src ? ' anp--video' : ''));+ var panel = el('section', 'anp'); panel.setAttribute('aria-label', 'Say it: sample prompts for ' + appName); var head = el('div', 'anp-head');@@ -360,26 +348,14 @@ panel.appendChild(head); var left = el('div', 'anp-left');- var controls = left;- if (videoCfg && videoCfg.src) {- video = el('video', 'anp-video');- video.src = videoCfg.src;- if (videoCfg.poster) video.poster = videoCfg.poster;- video.controls = true; video.playsInline = true; video.preload = 'none';- video.setAttribute('aria-label', videoCfg.title || 'Demonstration video');- left.appendChild(video);- controls = el('div', 'anp-video-toolbar');- left.appendChild(controls);- } var demo = el('button', 'anp-demo', ICON.play + '<span>' + esc((cfg.demo && cfg.demo.label) || 'Play the demo') + '</span>'); demo.type = 'button'; demo.addEventListener('click', function () {- if (video) video.play().catch(function () { toast('Press Play on the video to start playback.', 'info'); });- else if (cfg.demo && typeof cfg.demo.onPlay === 'function') cfg.demo.onPlay();+ if (cfg.demo && typeof cfg.demo.onPlay === 'function') cfg.demo.onPlay(); else toast('This dashboard has no demo wired up yet', 'err'); });- controls.appendChild(demo);- if (cfg.demo && cfg.demo.meta) controls.appendChild(el('span', 'anp-meta', esc(cfg.demo.meta)));+ left.appendChild(demo);+ if (cfg.demo && cfg.demo.meta) left.appendChild(el('span', 'anp-meta', esc(cfg.demo.meta))); panel.appendChild(left); var right = el('div', 'anp-right');@@ -438,7 +414,6 @@ * open pins it open forever and graduating it closed marks it user-dismissed. It looks * like "the panel sometimes ignores graduation". (lbr, 2026-08-25) */ function setOpen(open, remember, source) {- if (!open && video) video.pause(); panel.hidden = !open; wrap.style.display = open ? '' : 'none'; /* no dead margin when collapsed */ if (toggleBtn) {@@ -485,7 +460,7 @@ close: function (o) { setOpen(false, !(o && o.remember === false), 'api'); }, toggle: function () { setOpen(panel.hidden, true, 'api'); }, isOpen: function () { return !panel.hidden; },- video: video, overBudget: over, toast: toast, selfCheck: function () { return selfCheck(panel); }+ overBudget: over, toast: toast, selfCheck: function () { return selfCheck(panel); } }; } @@ -560,22 +535,8 @@ if (!aligned) ok = false; rows.push({ what: 'copy icons in one column', want: '1 x-position', got: Object.keys(xs).length + ' x-positions', pass: aligned }); var cols = cs.gridTemplateColumns.split(' ').filter(Boolean).length;- var withVideo = panel.classList.contains('anp--video');- var expectedCols = panel.parentElement.clientWidth >= (withVideo ? 1100 : TWO_COL_MIN) ? 2 : 1;- var colsOk = cols === expectedCols;- if (!colsOk) ok = false;- rows.push({ what: 'columns at this width', want: String(expectedCols), got: String(cols), pass: colsOk });- if (withVideo) {- var vr = panel.querySelector('.anp-video').getBoundingClientRect();- var lr = panel.querySelector('.anp-left').getBoundingClientRect();- var rr = panel.querySelector('.anp-right').getBoundingClientRect();- var mediaOk = Math.abs(vr.width - lr.width) < 2 && vr.width >= Math.min(300, lr.width) &&- Math.abs(vr.height - vr.width * 9 / 16) < 2 &&- (expectedCols === 1 ? rr.top >= lr.bottom - 1 : rr.left >= vr.right);- if (!mediaOk) ok = false;- rows.push({what:'video size and placement', want:'16:9, fills its column, no prompt overlap',- got:Math.round(vr.width)+' × '+Math.round(vr.height)+'px', pass:mediaOk});- }+ rows.push({ what: 'columns at this width', want: panel.getBoundingClientRect().width >= TWO_COL_MIN ? '2' : '1',+ got: String(cols), pass: true }); /* THE GUTTER ROW. Four apps measured at the SAME 744px pane reported panel widths of * 734, 735, 702 and 694, because each page put a different amount of its own padding * around the mount point. 694 is under the 700 threshold, so that app rendered ONE@@ -643,12 +604,7 @@ * remeasured with this probe, neither had less than 141px of slack. A metric that can only * return one value on success is not evidence of success. */ var spans = [].slice.call(panel.querySelectorAll('.anp-phrase span'));- if (withVideo && spans.length) {- var wrapOk = spans.every(function (sp) { return sp.scrollWidth <= sp.clientWidth + 1 &&- getComputedStyle(sp).whiteSpace === 'normal'; });- if (!wrapOk) ok = false;- rows.push({what:'readable video-panel prompts',want:'wrap without horizontal clipping',got:wrapOk?'all readable':'clipped or nowrap',pass:wrapOk});- } else if (spans.length) {+ if (spans.length) { var probe = document.createElement('span'); probe.style.cssText = 'position:absolute;visibility:hidden;white-space:nowrap;font:' + getComputedStyle(spans[0]).font;@@ -733,6 +689,6 @@ } root.AdomNewbiePanel = { mount: mount, toast: toast, selfCheck: selfCheck, copyText: copyText,- checkSend: checkSend, version: '2.23.0',+ checkSend: checkSend, version: '2.22.0', TWO_COL_MIN: TWO_COL_MIN, PHRASE_BUDGET: PHRASE_BUDGET }; })(typeof window !== 'undefined' ? window : this);