first-class-sessions (and the template)
change mmzoslyuwovwoowxqppzyvuxymvurtyv
commit 1327039766939eb9ed8954c062c986a27425ad54
author Alpha Chen <alpha@kejadlen.dev>
date
diff --git a/_render.html b/_render.html
new file mode 100644
index 0000000..4dee485
--- /dev/null
+++ b/_render.html
@@ -0,0 +1,183 @@
+{{$path := .OriginalReq.URL.Path -}}
+{{$file := printf "%s.md" (trimSuffix "/" $path) -}}
+{{if not (fileExists $file)}}{{httpError 404}}{{end -}}
+{{$doc := include $file | splitFrontMatter -}}
+<!doctype html>
+<html lang="en">
+<head>
+<meta charset="utf-8">
+<meta name="viewport" content="width=device-width, initial-scale=1">
+<meta name="color-scheme" content="light dark">
+<title>{{default (trimSuffix ".md" $file) $doc.Meta.title}} — kejadlen.dev</title>
+{{with $doc.Meta.description}}<meta name="description" content="{{.}}">
+{{end}}<script>try{var t=localStorage.getItem("theme");if(t)document.documentElement.dataset.theme=t}catch(e){}</script>
+<style>
+/* alphabaster — palette from kejadlen/dotfiles (.config/ghostty/config) */
+
+/* light-dark() reads color-scheme, so data-theme below is all the switch sets. */
+:root {
+	color-scheme: light dark;
+	--bg: light-dark(#F0F0E4, #121218);
+	--fg: light-dark(#121218, #F0F0E4);
+	--muted: light-dark(#63635C, #888888);
+	--border: light-dark(#C7C7B8, #44475A);
+	--lavender: light-dark(#6B4CA8, #C4AAEA);
+	--lavender-bright: light-dark(#513787, #D0BCF0);
+	--cyan: light-dark(#1F6B7A, #A2D6E0);
+	--green: light-dark(#28702C, #7BC275);
+	--red: light-dark(#B3261E, #E97C7C);
+	--code-bg: light-dark(#E4E4D6, #282A36);
+	--selection-bg: light-dark(#C6D0F5, #626880);
+	--selection-fg: light-dark(#303446, #c6d0f5);
+}
+
+:root[data-theme="light"] { color-scheme: light; }
+:root[data-theme="dark"] { color-scheme: dark; }
+
+* { box-sizing: border-box; }
+
+::selection { background: var(--selection-bg); color: var(--selection-fg); }
+
+a:focus-visible, button:focus-visible { outline: 2px solid var(--cyan); }
+
+#theme {
+	position: fixed;
+	top: 1rem;
+	right: 1rem;
+	width: 2.25rem;
+	height: 2.25rem;
+	background: var(--code-bg);
+	color: var(--fg);
+	border: 1px solid var(--border);
+	border-radius: 50%;
+	font-size: 1rem;
+	line-height: 1;
+	cursor: pointer;
+}
+
+#theme:hover { border-color: var(--lavender); }
+
+@media print { #theme { display: none; } }
+
+body {
+	margin: 0 auto;
+	padding: 2rem 1rem 4rem;
+	max-width: 44rem;
+	background: var(--bg);
+	color: var(--fg);
+	font: 16px/1.6 -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif;
+}
+
+/* Narrow viewports have no side margin for the button to sit in. */
+@media (max-width: 50rem) { body { padding-top: 4rem; } }
+
+a { color: var(--lavender); }
+a:hover { color: var(--lavender-bright); }
+
+h1, h2, h3, h4, h5, h6 { color: var(--cyan); line-height: 1.25; margin: 1.5em 0 0.5em; }
+h1:first-child { margin-top: 0; }
+
+blockquote {
+	border-left: 3px solid var(--border);
+	margin-left: 0;
+	padding-left: 1rem;
+	color: var(--muted);
+}
+
+code, pre, kbd { font-family: ui-monospace, "SF Mono", Menlo, Consolas, monospace; font-size: 0.9em; }
+
+code {
+	background: var(--code-bg);
+	color: var(--lavender);
+	padding: 0.15em 0.35em;
+	border-radius: 4px;
+}
+
+pre {
+	background: var(--code-bg);
+	border: 1px solid var(--border);
+	border-radius: 8px;
+	padding: 1rem;
+	overflow-x: auto;
+	line-height: 1.5;
+}
+
+pre code { background: none; padding: 0; color: inherit; }
+
+hr { border: 0; border-top: 1px solid var(--border); }
+
+table { border-collapse: collapse; }
+th, td { border: 1px solid var(--border); padding: 0.25rem 0.75rem; }
+
+img { max-width: 100%; }
+
+ul { padding-left: 1.5rem; }
+
+/*
+ * chroma — alphabaster: only comments, strings and constants, and
+ * definitions get color; keywords and operators stay default fg.
+ */
+.chroma .c, .chroma .c1, .chroma .c2, .chroma .ch, .chroma .cm, .chroma .cp, .chroma .cs {
+	color: var(--muted);
+}
+
+.chroma .s, .chroma .s1, .chroma .s2, .chroma .sa, .chroma .sb, .chroma .sc,
+.chroma .sd, .chroma .se, .chroma .sf, .chroma .sh, .chroma .si, .chroma .sj,
+.chroma .sr, .chroma .ss, .chroma .sx,
+.chroma .m, .chroma .mb, .chroma .mf, .chroma .mh, .chroma .mi, .chroma .mo, .chroma .mx,
+.chroma .kc, .chroma .no {
+	color: var(--lavender);
+}
+
+.chroma .fm, .chroma .nc, .chroma .ne, .chroma .nf, .chroma .nl, .chroma .nn {
+	color: var(--cyan);
+}
+
+.chroma .gi { color: var(--green); }
+.chroma .gd { color: var(--red); }
+.chroma .err { color: var(--red); }
+.chroma .ge { font-style: italic; }
+.chroma .gs { font-weight: bold; }
+</style>
+</head>
+<body>
+<button id="theme" hidden></button>
+<article>
+{{$doc.Body | markdown}}
+</article>
+<script>
+(function () {
+	var root = document.documentElement;
+	var btn = document.getElementById("theme");
+	var system = matchMedia("(prefers-color-scheme: dark)");
+
+	function effective() {
+		return root.dataset.theme || (system.matches ? "dark" : "light");
+	}
+
+	function label() {
+		var next = effective() === "dark" ? "light" : "dark";
+		btn.textContent = next === "dark" ? "☽" : "☀";
+		btn.setAttribute("aria-label", "Switch to " + next + " theme");
+	}
+
+	btn.addEventListener("click", function () {
+		var next = effective() === "dark" ? "light" : "dark";
+		// Matching the system again drops back to following it.
+		if (next === (system.matches ? "dark" : "light")) {
+			delete root.dataset.theme;
+			try { localStorage.removeItem("theme"); } catch (e) {}
+		} else {
+			root.dataset.theme = next;
+			try { localStorage.setItem("theme", next); } catch (e) {}
+		}
+		label();
+	});
+
+	system.addEventListener("change", label);
+	label();
+	btn.hidden = false;
+})();
+</script>
+</body>
+</html>
diff --git a/first-class-sessions.md b/first-class-sessions.md
new file mode 100644
index 0000000..a035566
--- /dev/null
+++ b/first-class-sessions.md
@@ -0,0 +1,67 @@
+# First-class sessions
+
+This is a vision of how software teams work with coding agents: an idea
+held apart from any particular tool or project.
+
+Teams collaborate on agent work through the pull request today, and the
+pull request arrives too late: by the time anyone else can look, the
+intent, the conversation, and the dead ends have already evaporated,
+leaving a diff and a description of it. Collaboration does reach earlier
+than that — an agent working a chat thread already has people steering it
+together — but a thread stands apart from the changes it produces, and it
+fades as the channel scrolls on.
+
+The central claim is that the session is first-class: the primary
+component of agent-driven software work. A session is the whole unit: who
+asked for what, the conversation that steered the work, the actions agents
+and people took along the way, and the changes that came out of it. It is
+durable and addressable, at a URL that works while the work is happening
+and keeps working after. Everything else derives from the session — a pull
+request is one export of it, not the frame around it.
+
+## What changes when this works
+
+- Collaboration moves earlier, until review stops being a separate stage.
+  People join, watch, and steer work while it happens, and the session
+  absorbs review: by the time the work is done, the people who needed to
+  look already have.
+- Agent work becomes legible. A session keeps the wrong turns along with
+  the result, so a team can learn from how the work went and not only from
+  what landed.
+- Sessions feed the system's own improvement. A durable record of real
+  work — the ask, the steering, the corrections, the outcome — is an eval
+  corpus nobody had to construct: replay a past session against a new
+  agent, prompt, or policy and compare how the work goes, or mine sessions
+  for where agents stalled and where people had to step in. The same
+  record that makes work legible to the team lets the tooling study and
+  improve itself.
+- Work forks. A session is a starting point as well as a record: a new
+  session branched off an existing one carries its context and its
+  changes, so exploring an alternative does not mean starting over.
+- Sessions are context for other sessions. Anything in the ecosystem can
+  reach the session that produced a change, so reviewing agents can examine
+  work with the exact history of how it came to be, or deliberately without
+  it — blind review becomes a choice rather than the default. The
+  examination is itself a session, one the original work can consult in
+  turn.
+- Every participant is a peer on one record. Humans, agents, and channels
+  (a chat thread can be a participant) act through attributed turns, and
+  the session's own log of who did what is the shared truth.
+- Capability flows through the session. An agent holds nothing of its own;
+  it asks the session for what it needs (a repository, a pull request, a
+  build) and the grant carries the authority of the person behind the ask.
+  Shared sessions make this necessary: once several people are present,
+  "who may do this" has to have an answer.
+
+## What this is not
+
+- An agent framework. Agents are built elsewhere and reason however they
+  reason; the session decides what they may do.
+- A pipeline runner. Automation can open a session — a schedule, an alert,
+  a failing build — but what it opens is a session like any other, one
+  that people can join and steer. Work nobody could join is a different
+  tool.
+- A hosted product. It runs where the team runs, inside the team's own
+  trust boundary.
+
+_Composed by Claude_