Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,13 @@ Notable changes to KERNEL, KERNEL·A (the agent), and KERNEL·M (the phone build

## [Unreleased]

### Phones
- Opening KERNEL·A on a phone opens KERNEL·M, the same app laid out for touch, with the same notebooks and the same link parameters, so example links work too. `?layout=desktop` keeps the desktop layout for the tab, and the app menu's KERNEL·A entry uses it.
- KERNEL·M is much denser. The header is one 32px row with every toolbar action under ⋯, code is 12px in a 32px gutter, markdown uses the full width, and cells, tables, outputs, the first-run card, the tab bar and every sheet are tighter. The agent's transcript runs edge to edge. Files and Variables sheets fit their contents. On iOS the viewport stops focus zoom, so fields no longer need 16px type.
- RUN ALL in the tab bar is lit only while the run lasts; it used to stay highlighted.
- On touch screens, COPY, CSV and PNG sit under an output instead of covering it. The iOS install hint hides itself after a few seconds, and toasts stay above it.
- The desktop layout holds together in narrow windows: the header takes two rows with a sideways-scrolling toolbar, and the footer wraps.

### Getting started
- Example links: `kernel-agent.html?example=<name>` opens one of the curated runs in `examples/` with its original outputs, in a new notebook if the current one has work in it. The welcome card has a *See a real agent run* button, and the landing page and README link all four. Fleet DNA reads public data the repository doesn't include, so it links to where to get it.
- A demo of an agent run at the top of the README and the landing page, recorded by `npm run demo`.
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ They were captured with KERNEL Agent 2.3.0. The published notebooks keep the vis

## Use it

**The apps** are single HTML files. Open them from the [live page](https://dogum.github.io/kernel/), download one from [`docs/`](docs/) and open it locally, or put it on any static host. Pyodide downloads about 10 MB on first run and is cached after. Installing KERNEL·M to a home screen and using it offline need https, which GitHub Pages provides.
**The apps** are single HTML files. Open them from the [live page](https://dogum.github.io/kernel/), download one from [`docs/`](docs/) and open it locally, or put it on any static host. Pyodide downloads about 10 MB on first run and is cached after. Installing KERNEL·M to a home screen and using it offline need https, which GitHub Pages provides. On a phone, KERNEL·A opens as KERNEL·M; add `?layout=desktop` to keep the desktop layout.

**The agent** needs an API key from Anthropic, OpenAI, or xAI; add it in the agent's settings. Keys stay in your browser and requests go straight to the provider (or a compatible gateway you choose).

Expand Down
216 changes: 151 additions & 65 deletions docs/kernel-agent-mobile.html

Large diffs are not rendered by default.

51 changes: 46 additions & 5 deletions docs/kernel-agent.html
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,24 @@
<html lang="en">
<head>
<script>try{document.documentElement.dataset.theme=localStorage.getItem("ut-theme")||"light"}catch(e){document.documentElement.dataset.theme="light"}</script>
<script>
/* Phones get KERNEL·M, the same app laid out for touch (tab bar, bottom sheets), with the same notebooks and the same
link parameters. ?layout=desktop keeps this layout for the rest of the tab's session. */
try {
(function () {
var q = new URLSearchParams(location.search), key = "kernel.layout";
if (q.get("layout") === "desktop") {
sessionStorage.setItem(key, "desktop");
q.delete("layout");
history.replaceState(null, "", location.pathname + (String(q) ? "?" + q : "") + location.hash);
return;
}
if (sessionStorage.getItem(key) === "desktop") return;
if (matchMedia("(pointer:coarse)").matches && Math.min(screen.width, screen.height) <= 600)
location.replace("kernel-agent-mobile.html" + location.search + location.hash);
})();
} catch (e) {}
</script>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>KERNEL·A v2.4.0 — durable agentic notebook, in a single file</title>
Expand Down Expand Up @@ -549,7 +567,7 @@
.out{position:relative}
.out-acts{position:absolute;top:6px;right:8px;display:flex;gap:4px;opacity:0;transition:opacity .12s;z-index:2}
.out:hover .out-acts,.out:focus-within .out-acts{opacity:1}
@media (hover:none){.out-acts{opacity:.85}}
@media (hover:none){.out-acts{position:static;opacity:1;justify-content:flex-end;margin-top:5px}} /* no hover on touch: a row under the output, never over it */
.out-acts button{font:600 9.5px var(--mono);letter-spacing:.06em;color:var(--ink-3);background:var(--surface);border:1px solid var(--line-2);border-radius:3px;padding:3px 7px;cursor:pointer}
.out-acts button:hover{color:var(--accent);border-color:var(--accent)}
.out.long{max-height:460px}
Expand Down Expand Up @@ -687,12 +705,26 @@
.toolbar #btnNew,.toolbar #btnOpen,.toolbar #btnWorkspace,.toolbar #btnClear{display:none}
.menu-item.narrow-only{display:block}.menu-sep.narrow-only{display:block}
}
/* Narrow windows (and ?layout=desktop on a phone): the header takes two rows, with the toolbar scrolling sideways
instead of stacking into a column, and the footer wraps. Phones normally get KERNEL·M instead. */
@media (max-width:760px){
.topbar{flex-wrap:wrap; gap:6px 8px; padding:7px 10px}
.brand{min-width:0; flex:1 1 auto}
.brand .brand-v{display:none}
.nb-pill{min-width:0; max-width:none}
.toolbar{flex:1 1 100%; flex-wrap:nowrap; justify-content:flex-start; margin-left:0; overflow-x:auto; scrollbar-width:none}
.toolbar::-webkit-scrollbar{display:none}
.toolbar .menu-wrap{position:static}
.toolbar .menu{top:100%; right:8px; margin-top:2px} /* anchored to the header, so the scrolling toolbar can't clip it */
.sheet{padding:12px 8px 96px}
.foot{flex-wrap:wrap; gap:3px 12px; padding:5px 10px}
}
</style>
</head>
<body>
<div id="progress" class="progress" aria-hidden="true"></div>
<header class="topbar">
<div class="brand"><h1><button class="brand-btn" id="suiteBtn" type="button" aria-haspopup="menu" aria-expanded="false" aria-controls="suiteMenu" title="Switch app, project page, theme (Alt+K)"><span class="mark"></span><span class="brand-name">KERNEL<span class="brand-a">·A v2.4.0</span></span><svg class="brand-chev" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M4 6l4 4 4-4"/></svg></button></h1>
<div class="brand"><h1><button class="brand-btn" id="suiteBtn" type="button" aria-haspopup="menu" aria-expanded="false" aria-controls="suiteMenu" title="Switch app, project page, theme (Alt+K)"><span class="mark"></span><span class="brand-name">KERNEL<span class="brand-a">·A<span class="brand-v"> v2.4.0</span></span></span><svg class="brand-chev" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M4 6l4 4 4-4"/></svg></button></h1>
<button class="nb-pill" id="nbTitle" title="Notebooks (switch / rename / new)">
<svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.4"><path d="M1.8 4.2c0-.6.5-1.1 1.1-1.1h3l1.3 1.4h5c.6 0 1.1.5 1.1 1.1v6.1c0 .6-.5 1.1-1.1 1.1H2.9c-.6 0-1.1-.5-1.1-1.1z"/></svg>
<span id="nbTitleText">Untitled</span>
Expand Down Expand Up @@ -6359,6 +6391,8 @@ <h3>Command mode</h3>
if (a === "newNb") newNotebook();
else if (a === "openNb") $("#btnOpen").click();
else if (a === "saveZip") downloadWorkspaceZip();
else if (a === "saveIpynb") downloadIpynb();
else if (a === "restart") restartKernel();
else if (a === "restartRun") restartAndRunAll();
else if (a === "splitOut") setSplitOutputs(!ui.splitOutputs);
else if (a === "collapseAll") setAllCollapsed(true);
Expand Down Expand Up @@ -12746,9 +12780,10 @@ <h3>Command mode</h3>
<div id="suiteMenu" role="menu" aria-label="KERNEL apps"></div>
<script>
(function () {
// [file, name, description, link when it isn't the file name]
var SUITE = [
["kernel.html", "KERNEL", "The notebook, no agent"],
["kernel-agent.html", "KERNEL·A", "Notebook with an AI agent"],
["kernel-agent.html", "KERNEL·A", "Notebook with an AI agent", "kernel-agent.html?layout=desktop"],
["kernel-agent-mobile.html", "KERNEL·M", "The agent, built for phones"],
];
var here = decodeURIComponent(location.pathname.split("/").pop() || "");
Expand Down Expand Up @@ -12786,7 +12821,13 @@ <h3>Command mode</h3>
"</b><span>" +
t[2] +
'</span><i aria-hidden="true">✓</i></button>'
: '<a class="sm-item" role="menuitem" href="' + t[0] + '"><b>' + t[1] + "</b><span>" + t[2] + "</span></a>";
: '<a class="sm-item" role="menuitem" href="' +
(t[3] || t[0]) +
'"><b>' +
t[1] +
"</b><span>" +
t[2] +
"</span></a>";
}).join("") +
'<div class="sm-sep" role="separator"></div>' +
'<a class="sm-item sm-util" role="menuitem" href="index.html"><span>Project page</span><kbd>' +
Expand Down Expand Up @@ -12830,7 +12871,7 @@ <h3>Command mode</h3>
}
function step(d) {
var i = cur >= 0 ? (cur + d + SUITE.length) % SUITE.length : 0;
location.href = SUITE[i][0];
location.href = SUITE[i][3] || SUITE[i][0];
}
btn.addEventListener("click", function (e) {
e.stopPropagation();
Expand Down
6 changes: 3 additions & 3 deletions docs/kernel.html
Original file line number Diff line number Diff line change
Expand Up @@ -2569,7 +2569,7 @@ <h3>Command mode</h3>
<div id="suiteMenu" role="menu" aria-label="KERNEL apps"></div>
<script>
(function(){
var SUITE=[["kernel.html","KERNEL","The notebook, no agent"],["kernel-agent.html","KERNEL·A","Notebook with an AI agent"],["kernel-agent-mobile.html","KERNEL·M","The agent, built for phones"]];
var SUITE=[["kernel.html","KERNEL","The notebook, no agent"],["kernel-agent.html","KERNEL·A","Notebook with an AI agent","kernel-agent.html?layout=desktop"],["kernel-agent-mobile.html","KERNEL·M","The agent, built for phones"]];
var here=decodeURIComponent(location.pathname.split('/').pop()||'');
var cur=SUITE.findIndex(function(t){return t[0]===here});
var mac=/Mac|iPhone|iPad/.test(navigator.platform||navigator.userAgent||'');
Expand All @@ -2581,7 +2581,7 @@ <h3>Command mode</h3>
function paint(focusKey){
menu.innerHTML='<div class="sm-label">KERNEL apps</div>'+SUITE.map(function(t,i){
return i===cur?'<button type="button" class="sm-item cur" role="menuitem" aria-current="page" data-sm="close"><b>'+t[1]+'</b><span>'+t[2]+'</span><i aria-hidden="true">✓</i></button>'
:'<a class="sm-item" role="menuitem" href="'+t[0]+'"><b>'+t[1]+'</b><span>'+t[2]+'</span></a>';
:'<a class="sm-item" role="menuitem" href="'+(t[3]||t[0])+'"><b>'+t[1]+'</b><span>'+t[2]+'</span></a>';
}).join('')+'<div class="sm-sep" role="separator"></div>'
+'<a class="sm-item sm-util" role="menuitem" href="index.html"><span>Project page</span><kbd>'+hint('I')+'</kbd></a>'
+'<button type="button" class="sm-item sm-util" role="menuitem" data-sm="theme"><span>'+(document.documentElement.dataset.theme==='dark'?'Light theme':'Dark theme')+'</span><kbd>'+hint('T')+'</kbd></button>';
Expand All @@ -2591,7 +2591,7 @@ <h3>Command mode</h3>
function place(){var r=btn.getBoundingClientRect();menu.style.top=Math.round(r.bottom+8)+'px';menu.style.left=Math.round(Math.max(8,Math.min(r.left-6,innerWidth-menu.offsetWidth-8)))+'px'}
function open(){paint();menu.classList.add('open');btn.setAttribute('aria-expanded','true');place();var it=items(),f=it.filter(function(x){return !x.classList.contains('cur')})[0]||it[0];if(f)f.focus()}
function close(refocus){if(!isOpen())return;menu.classList.remove('open');btn.setAttribute('aria-expanded','false');if(refocus)btn.focus()}
function step(d){var i=cur>=0?(cur+d+SUITE.length)%SUITE.length:0;location.href=SUITE[i][0]}
function step(d){var i=cur>=0?(cur+d+SUITE.length)%SUITE.length:0;location.href=SUITE[i][3]||SUITE[i][0]}
btn.addEventListener('click',function(e){e.stopPropagation();isOpen()?close():open()});
menu.addEventListener('click',function(e){var it=e.target.closest('[data-sm]');if(!it)return;if(it.getAttribute('data-sm')==='theme')flipTheme();else close(true)});
menu.addEventListener('keydown',function(e){
Expand Down
2 changes: 1 addition & 1 deletion src/agent/css/agent.css

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

14 changes: 14 additions & 0 deletions src/agent/css/desktop.css
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,17 @@
.toolbar #btnNew,.toolbar #btnOpen,.toolbar #btnWorkspace,.toolbar #btnClear{display:none}
.menu-item.narrow-only{display:block}.menu-sep.narrow-only{display:block}
}
/* Narrow windows (and ?layout=desktop on a phone): the header takes two rows, with the toolbar scrolling sideways
instead of stacking into a column, and the footer wraps. Phones normally get KERNEL·M instead. */
@media (max-width:760px){
.topbar{flex-wrap:wrap; gap:6px 8px; padding:7px 10px}
.brand{min-width:0; flex:1 1 auto}
.brand .brand-v{display:none}
.nb-pill{min-width:0; max-width:none}
.toolbar{flex:1 1 100%; flex-wrap:nowrap; justify-content:flex-start; margin-left:0; overflow-x:auto; scrollbar-width:none}
.toolbar::-webkit-scrollbar{display:none}
.toolbar .menu-wrap{position:static}
.toolbar .menu{top:100%; right:8px; margin-top:2px} /* anchored to the header, so the scrolling toolbar can't clip it */
.sheet{padding:12px 8px 96px}
.foot{flex-wrap:wrap; gap:3px 12px; padding:5px 10px}
}
Loading
Loading