chore: renormalize line endings under the new .gitattributes

Line-ending only. Verified: 3667 insertions against 3667 deletions with
zero content difference under --ignore-cr-at-eol.
This commit is contained in:
meels
2026-07-28 15:20:55 +02:00
parent 51c85e6994
commit 5de50b155a
12 changed files with 3667 additions and 3667 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -1,9 +1,9 @@
{
"id": "webinar-dash",
"name": "Webinar dashboard",
"version": "0.1.0",
"minAppVersion": "1.5.0",
"description": "Source pipeline and script coverage for the webinar vault.",
"author": "meels",
"isDesktopOnly": true
}
{
"id": "webinar-dash",
"name": "Webinar dashboard",
"version": "0.1.0",
"minAppVersion": "1.5.0",
"description": "Source pipeline and script coverage for the webinar vault.",
"author": "meels",
"isDesktopOnly": true
}

View File

@@ -1,239 +1,239 @@
.webinar-dash {
--wd-ink-000: #ffffff; --wd-ink-050: #f7f7f7; --wd-ink-100: #ececec;
--wd-ink-200: #d9d9d9; --wd-ink-400: #8a8a8a; --wd-ink-500: #5e5e5e;
--wd-ink-700: #262626; --wd-ink-900: #0a0a0a; --wd-ink-999: #000000;
--wd-red-500: #e1261c; --wd-red-600: #c31c14;
--wd-bg: var(--wd-ink-000);
--wd-bg-subtle: var(--wd-ink-050);
--wd-fg: var(--wd-ink-999);
--wd-fg-2: var(--wd-ink-700);
--wd-fg-3: var(--wd-ink-500);
--wd-fg-4: var(--wd-ink-400);
--wd-border: var(--wd-ink-200);
--wd-border-strong: var(--wd-ink-999);
--wd-border-subtle: var(--wd-ink-100);
--wd-accent: var(--wd-red-500);
--wd-accent-press: var(--wd-red-600);
--wd-accent-on: #ffffff;
--wd-ok: #0a8a3f;
--wd-warn: #c68a00;
--wd-danger: var(--wd-red-500);
--wd-mono: "JetBrains Mono", ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
--wd-sans: "Inter", ui-sans-serif, system-ui, -apple-system, "Helvetica Neue", Arial, sans-serif;
font-family: var(--wd-sans);
color: var(--wd-fg);
display: flex;
flex-direction: column;
gap: 16px;
/* Past roughly this width the two panes stop reading as a pair and table
rows get hard to track across. Cap the whole dashboard, not just the
grid, so the toolbar stays flush with the panes below it. */
max-width: 1600px;
/* Makes this element the reference for the @container query further down,
so the grid collapses on the pane's width rather than the window's. */
container-type: inline-size;
}
.theme-dark .webinar-dash {
--wd-bg: var(--wd-ink-900);
--wd-bg-subtle: #161616;
--wd-fg: var(--wd-ink-000);
--wd-fg-2: var(--wd-ink-200);
--wd-fg-3: var(--wd-ink-400);
--wd-fg-4: var(--wd-ink-500);
--wd-border: var(--wd-ink-700);
--wd-border-strong: #b8b8b8;
--wd-border-subtle: #161616;
/* Accent tracks the installed theme at .obsidian/themes/tesanti/theme.css,
whose dark section reads "Black canvas, same signal red": --accent-h/-s/-l
are declared once at :root and never redeclared under .theme-dark, and only
the hover state lifts (#c31c14 light, #ff4d43 dark). Match that exactly. */
--wd-accent: var(--wd-red-500);
--wd-accent-press: #ff4d43;
--wd-accent-on: #ffffff;
/* Status tokens are separate from the brand accent by design-system rule, and
here they carry small text in a dense table. #e1261c on near-black is about
3.8:1, under AA for small text, so these lift where the accent does not. */
--wd-ok: #2fbf6a;
--wd-warn: #e0a516;
--wd-danger: #ff5c50;
}
/* ------------------------------------------------------------------
Escape Obsidian's readable-line-length cap.
With "Readable line length" on (the default), Obsidian caps note
content at --file-line-width, roughly 700px. That is right for prose
and wrong for a two-pane dashboard, which gets squeezed into a column.
:has() scopes this to the sizer that actually contains a dashboard, so
every other note in the vault keeps its readable width. Both selectors
are needed: reading view sizes on .markdown-preview-sizer, live preview
on .cm-sizer.
If you would rather not rely on this, the alternatives are Settings ->
Editor -> Readable line length (off, but that widens every note), or
adding `cssclasses: wide-dash` to the note's frontmatter and swapping
the :has() selectors below for `.wide-dash .markdown-preview-sizer`.
------------------------------------------------------------------ */
.markdown-preview-sizer:has(.webinar-dash),
.markdown-source-view.mod-cm6 .cm-sizer:has(.webinar-dash) {
max-width: none;
}
.wd-grid {
display: grid;
grid-template-columns: minmax(0, 38fr) minmax(0, 62fr);
gap: 24px;
}
.wd-grid > * { min-width: 0; }
.wd-bar {
display: flex;
align-items: center;
gap: 12px;
flex-wrap: wrap;
border: 1px solid var(--wd-border);
border-radius: 4px;
padding: 8px 12px;
background: var(--wd-bg-subtle);
}
.wd-btn-ghost {
background: transparent;
color: var(--wd-fg);
border-color: var(--wd-border-strong);
}
.wd-btn-ghost:hover {
background: var(--wd-bg-muted, var(--wd-bg-subtle));
border-color: var(--wd-border-strong);
}
/* Collapse to one column on the width that actually matters — the pane's,
not the window's. A media query measures the window, so a wide window
with the dashboard in a narrow split pane would keep two cramped
columns. The container query below responds to the pane itself; the
media query stays as a floor for a genuinely narrow window. */
@container (max-width: 820px) {
.wd-grid { grid-template-columns: minmax(0, 1fr); }
}
@media (max-width: 820px) {
.wd-grid { grid-template-columns: minmax(0, 1fr); }
}
.wd-pane { display: flex; flex-direction: column; gap: 20px; }
.wd-eyebrow {
font-family: var(--wd-mono); font-size: 11px; line-height: 1;
letter-spacing: 0.12em; text-transform: uppercase;
color: var(--wd-fg-3); font-weight: 500;
display: flex; align-items: center; gap: 8px;
}
.wd-eyebrow::before {
content: ""; width: 5px; height: 5px; flex: none; background: var(--wd-accent);
}
.wd-block { display: flex; flex-direction: column; gap: 12px; }
.wd-row {
display: flex; align-items: center; gap: 12px; flex-wrap: wrap;
border: 1px solid var(--wd-border); border-radius: 4px;
padding: 12px 12px 12px 16px; background: var(--wd-bg);
}
.wd-row + .wd-row { margin-top: -1px; }
.wd-row-main { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 2px; }
.wd-row-name {
font-size: 14px; font-weight: 600;
overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.wd-mono {
font-family: var(--wd-mono); font-size: 11px; color: var(--wd-fg-3);
font-variant-numeric: tabular-nums;
}
.wd-btn {
display: inline-flex; align-items: center; gap: 6px; flex: none;
font-family: var(--wd-sans); font-size: 13px; font-weight: 600;
padding: 6px 12px; border-radius: 6px; cursor: pointer;
border: 1px solid var(--wd-accent); background: var(--wd-accent);
color: var(--wd-accent-on);
transition: background 120ms cubic-bezier(0.2, 0, 0, 1);
}
.wd-btn:hover { background: var(--wd-accent-press); border-color: var(--wd-accent-press); }
.wd-btn:focus-visible { outline: 2px solid var(--wd-accent); outline-offset: 2px; }
.wd-btn[disabled] {
opacity: 0.45; cursor: not-allowed;
background: transparent; color: var(--wd-fg-3); border-color: var(--wd-border);
}
.wd-btn svg { width: 14px; height: 14px; flex: none; }
.wd-done { display: flex; flex-direction: column; }
.wd-done-row {
display: flex; align-items: baseline; gap: 12px; padding: 5px 0;
border-bottom: 1px solid var(--wd-border-subtle); font-size: 13px;
}
.wd-done-row:last-child { border-bottom: 0; }
.wd-done-name {
color: var(--wd-fg-2);
overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.wd-note { font-size: 12px; color: var(--wd-fg-3); }
.wd-error {
font-size: 13px; color: var(--wd-danger);
border: 1px solid var(--wd-danger); border-radius: 4px; padding: 12px;
}
@media (prefers-reduced-motion: reduce) {
.webinar-dash * { transition-duration: 0.01ms !important; }
}
.wd-meter { display: flex; gap: 2px; height: 8px; width: 100%; }
.wd-meter > i { display: block; height: 100%; }
.wd-seg-covered { background: var(--wd-ok); }
.wd-seg-partial { background: var(--wd-warn); }
.wd-seg-absent { background: var(--wd-danger); }
.wd-key { display: flex; flex-wrap: wrap; gap: 16px; font-size: 12px; color: var(--wd-fg-2); }
.wd-key > span { display: inline-flex; align-items: center; gap: 6px; }
.wd-key i { width: 8px; height: 8px; flex: none; }
.wd-tbl { width: 100%; border-collapse: collapse; font-size: 13px; }
.wd-tbl th {
font-family: var(--wd-mono); font-size: 10px; letter-spacing: 0.1em;
text-transform: uppercase; color: var(--wd-fg-3); font-weight: 500;
text-align: left; padding: 0 12px 8px 0;
border-bottom: 1px solid var(--wd-border-strong);
}
.wd-tbl td {
padding: 6px 12px 6px 0; border-bottom: 1px solid var(--wd-border-subtle);
vertical-align: baseline;
}
.wd-grp td {
padding-top: 16px; border-bottom: 1px solid var(--wd-border-strong);
font-family: var(--wd-mono); font-size: 10px; letter-spacing: 0.1em;
text-transform: uppercase; color: var(--wd-fg); font-weight: 500;
}
.wd-stat { display: inline-flex; align-items: center; gap: 5px; font-size: 12px; font-weight: 600; }
.wd-stat svg { width: 13px; height: 13px; flex: none; }
.wd-covered { color: var(--wd-ok); }
.wd-partial { color: var(--wd-warn); }
.wd-absent { color: var(--wd-danger); }
.wd-pin { font-family: var(--wd-mono); font-size: 10px; color: var(--wd-fg-4); }
.wd-status { font-family: var(--wd-mono); font-size: 11px; flex: none; }
.wd-status-running { color: var(--wd-warn); }
.wd-status-done { color: var(--wd-ok); }
.wd-status-failed { color: var(--wd-danger); }
.wd-output {
flex-basis: 100%;
width: 100%;
font-family: var(--wd-mono); font-size: 11px; white-space: pre-wrap;
max-height: 220px; overflow: auto; margin-top: 8px;
border: 1px solid var(--wd-border); border-radius: 4px; padding: 8px;
color: var(--wd-fg-2);
}
.webinar-dash {
--wd-ink-000: #ffffff; --wd-ink-050: #f7f7f7; --wd-ink-100: #ececec;
--wd-ink-200: #d9d9d9; --wd-ink-400: #8a8a8a; --wd-ink-500: #5e5e5e;
--wd-ink-700: #262626; --wd-ink-900: #0a0a0a; --wd-ink-999: #000000;
--wd-red-500: #e1261c; --wd-red-600: #c31c14;
--wd-bg: var(--wd-ink-000);
--wd-bg-subtle: var(--wd-ink-050);
--wd-fg: var(--wd-ink-999);
--wd-fg-2: var(--wd-ink-700);
--wd-fg-3: var(--wd-ink-500);
--wd-fg-4: var(--wd-ink-400);
--wd-border: var(--wd-ink-200);
--wd-border-strong: var(--wd-ink-999);
--wd-border-subtle: var(--wd-ink-100);
--wd-accent: var(--wd-red-500);
--wd-accent-press: var(--wd-red-600);
--wd-accent-on: #ffffff;
--wd-ok: #0a8a3f;
--wd-warn: #c68a00;
--wd-danger: var(--wd-red-500);
--wd-mono: "JetBrains Mono", ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
--wd-sans: "Inter", ui-sans-serif, system-ui, -apple-system, "Helvetica Neue", Arial, sans-serif;
font-family: var(--wd-sans);
color: var(--wd-fg);
display: flex;
flex-direction: column;
gap: 16px;
/* Past roughly this width the two panes stop reading as a pair and table
rows get hard to track across. Cap the whole dashboard, not just the
grid, so the toolbar stays flush with the panes below it. */
max-width: 1600px;
/* Makes this element the reference for the @container query further down,
so the grid collapses on the pane's width rather than the window's. */
container-type: inline-size;
}
.theme-dark .webinar-dash {
--wd-bg: var(--wd-ink-900);
--wd-bg-subtle: #161616;
--wd-fg: var(--wd-ink-000);
--wd-fg-2: var(--wd-ink-200);
--wd-fg-3: var(--wd-ink-400);
--wd-fg-4: var(--wd-ink-500);
--wd-border: var(--wd-ink-700);
--wd-border-strong: #b8b8b8;
--wd-border-subtle: #161616;
/* Accent tracks the installed theme at .obsidian/themes/tesanti/theme.css,
whose dark section reads "Black canvas, same signal red": --accent-h/-s/-l
are declared once at :root and never redeclared under .theme-dark, and only
the hover state lifts (#c31c14 light, #ff4d43 dark). Match that exactly. */
--wd-accent: var(--wd-red-500);
--wd-accent-press: #ff4d43;
--wd-accent-on: #ffffff;
/* Status tokens are separate from the brand accent by design-system rule, and
here they carry small text in a dense table. #e1261c on near-black is about
3.8:1, under AA for small text, so these lift where the accent does not. */
--wd-ok: #2fbf6a;
--wd-warn: #e0a516;
--wd-danger: #ff5c50;
}
/* ------------------------------------------------------------------
Escape Obsidian's readable-line-length cap.
With "Readable line length" on (the default), Obsidian caps note
content at --file-line-width, roughly 700px. That is right for prose
and wrong for a two-pane dashboard, which gets squeezed into a column.
:has() scopes this to the sizer that actually contains a dashboard, so
every other note in the vault keeps its readable width. Both selectors
are needed: reading view sizes on .markdown-preview-sizer, live preview
on .cm-sizer.
If you would rather not rely on this, the alternatives are Settings ->
Editor -> Readable line length (off, but that widens every note), or
adding `cssclasses: wide-dash` to the note's frontmatter and swapping
the :has() selectors below for `.wide-dash .markdown-preview-sizer`.
------------------------------------------------------------------ */
.markdown-preview-sizer:has(.webinar-dash),
.markdown-source-view.mod-cm6 .cm-sizer:has(.webinar-dash) {
max-width: none;
}
.wd-grid {
display: grid;
grid-template-columns: minmax(0, 38fr) minmax(0, 62fr);
gap: 24px;
}
.wd-grid > * { min-width: 0; }
.wd-bar {
display: flex;
align-items: center;
gap: 12px;
flex-wrap: wrap;
border: 1px solid var(--wd-border);
border-radius: 4px;
padding: 8px 12px;
background: var(--wd-bg-subtle);
}
.wd-btn-ghost {
background: transparent;
color: var(--wd-fg);
border-color: var(--wd-border-strong);
}
.wd-btn-ghost:hover {
background: var(--wd-bg-muted, var(--wd-bg-subtle));
border-color: var(--wd-border-strong);
}
/* Collapse to one column on the width that actually matters — the pane's,
not the window's. A media query measures the window, so a wide window
with the dashboard in a narrow split pane would keep two cramped
columns. The container query below responds to the pane itself; the
media query stays as a floor for a genuinely narrow window. */
@container (max-width: 820px) {
.wd-grid { grid-template-columns: minmax(0, 1fr); }
}
@media (max-width: 820px) {
.wd-grid { grid-template-columns: minmax(0, 1fr); }
}
.wd-pane { display: flex; flex-direction: column; gap: 20px; }
.wd-eyebrow {
font-family: var(--wd-mono); font-size: 11px; line-height: 1;
letter-spacing: 0.12em; text-transform: uppercase;
color: var(--wd-fg-3); font-weight: 500;
display: flex; align-items: center; gap: 8px;
}
.wd-eyebrow::before {
content: ""; width: 5px; height: 5px; flex: none; background: var(--wd-accent);
}
.wd-block { display: flex; flex-direction: column; gap: 12px; }
.wd-row {
display: flex; align-items: center; gap: 12px; flex-wrap: wrap;
border: 1px solid var(--wd-border); border-radius: 4px;
padding: 12px 12px 12px 16px; background: var(--wd-bg);
}
.wd-row + .wd-row { margin-top: -1px; }
.wd-row-main { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 2px; }
.wd-row-name {
font-size: 14px; font-weight: 600;
overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.wd-mono {
font-family: var(--wd-mono); font-size: 11px; color: var(--wd-fg-3);
font-variant-numeric: tabular-nums;
}
.wd-btn {
display: inline-flex; align-items: center; gap: 6px; flex: none;
font-family: var(--wd-sans); font-size: 13px; font-weight: 600;
padding: 6px 12px; border-radius: 6px; cursor: pointer;
border: 1px solid var(--wd-accent); background: var(--wd-accent);
color: var(--wd-accent-on);
transition: background 120ms cubic-bezier(0.2, 0, 0, 1);
}
.wd-btn:hover { background: var(--wd-accent-press); border-color: var(--wd-accent-press); }
.wd-btn:focus-visible { outline: 2px solid var(--wd-accent); outline-offset: 2px; }
.wd-btn[disabled] {
opacity: 0.45; cursor: not-allowed;
background: transparent; color: var(--wd-fg-3); border-color: var(--wd-border);
}
.wd-btn svg { width: 14px; height: 14px; flex: none; }
.wd-done { display: flex; flex-direction: column; }
.wd-done-row {
display: flex; align-items: baseline; gap: 12px; padding: 5px 0;
border-bottom: 1px solid var(--wd-border-subtle); font-size: 13px;
}
.wd-done-row:last-child { border-bottom: 0; }
.wd-done-name {
color: var(--wd-fg-2);
overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.wd-note { font-size: 12px; color: var(--wd-fg-3); }
.wd-error {
font-size: 13px; color: var(--wd-danger);
border: 1px solid var(--wd-danger); border-radius: 4px; padding: 12px;
}
@media (prefers-reduced-motion: reduce) {
.webinar-dash * { transition-duration: 0.01ms !important; }
}
.wd-meter { display: flex; gap: 2px; height: 8px; width: 100%; }
.wd-meter > i { display: block; height: 100%; }
.wd-seg-covered { background: var(--wd-ok); }
.wd-seg-partial { background: var(--wd-warn); }
.wd-seg-absent { background: var(--wd-danger); }
.wd-key { display: flex; flex-wrap: wrap; gap: 16px; font-size: 12px; color: var(--wd-fg-2); }
.wd-key > span { display: inline-flex; align-items: center; gap: 6px; }
.wd-key i { width: 8px; height: 8px; flex: none; }
.wd-tbl { width: 100%; border-collapse: collapse; font-size: 13px; }
.wd-tbl th {
font-family: var(--wd-mono); font-size: 10px; letter-spacing: 0.1em;
text-transform: uppercase; color: var(--wd-fg-3); font-weight: 500;
text-align: left; padding: 0 12px 8px 0;
border-bottom: 1px solid var(--wd-border-strong);
}
.wd-tbl td {
padding: 6px 12px 6px 0; border-bottom: 1px solid var(--wd-border-subtle);
vertical-align: baseline;
}
.wd-grp td {
padding-top: 16px; border-bottom: 1px solid var(--wd-border-strong);
font-family: var(--wd-mono); font-size: 10px; letter-spacing: 0.1em;
text-transform: uppercase; color: var(--wd-fg); font-weight: 500;
}
.wd-stat { display: inline-flex; align-items: center; gap: 5px; font-size: 12px; font-weight: 600; }
.wd-stat svg { width: 13px; height: 13px; flex: none; }
.wd-covered { color: var(--wd-ok); }
.wd-partial { color: var(--wd-warn); }
.wd-absent { color: var(--wd-danger); }
.wd-pin { font-family: var(--wd-mono); font-size: 10px; color: var(--wd-fg-4); }
.wd-status { font-family: var(--wd-mono); font-size: 11px; flex: none; }
.wd-status-running { color: var(--wd-warn); }
.wd-status-done { color: var(--wd-ok); }
.wd-status-failed { color: var(--wd-danger); }
.wd-output {
flex-basis: 100%;
width: 100%;
font-family: var(--wd-mono); font-size: 11px; white-space: pre-wrap;
max-height: 220px; overflow: auto; margin-top: 8px;
border: 1px solid var(--wd-border); border-radius: 4px; padding: 8px;
color: var(--wd-fg-2);
}

View File

@@ -1,122 +1,122 @@
"use strict";
const test = require("node:test");
const assert = require("node:assert/strict");
const { parseCoverageTable, groupByStation } = require("../main.js").__test__;
const DOC = [
"# Script coverage",
"",
"#coverage",
"",
"## Metadata",
"",
"- **Script:** `raw/sources/Webinar script.md`",
"- **Last synced:** 2026-07-28",
"",
"## Coverage",
"",
"| Concept | Status | Station | Pinned |",
"|---|---|---|---|",
"| [[harness]] | covered | Tools | |",
"| [[agentic-loops]] | partial | Process | |",
"| [[levels-of-ai-usage]] | partial | all | |",
"| [[connections-as-moat]] | absent | — | yes |",
].join("\n");
test("parseCoverageTable reads metadata", () => {
const { meta } = parseCoverageTable(DOC);
assert.equal(meta.script, "raw/sources/Webinar script.md");
assert.equal(meta.lastSynced, "2026-07-28");
});
test("parseCoverageTable reads every data row and skips the header", () => {
const { rows, errors } = parseCoverageTable(DOC);
assert.equal(errors.length, 0);
assert.equal(rows.length, 4);
assert.deepEqual(rows.map((r) => r.concept), [
"harness", "agentic-loops", "levels-of-ai-usage", "connections-as-moat",
]);
});
test("parseCoverageTable normalises stations", () => {
const { rows } = parseCoverageTable(DOC);
assert.deepEqual(rows[0].stations, ["Tools"]);
assert.deepEqual(rows[2].stations, ["all"]);
assert.deepEqual(rows[3].stations, []);
});
test("parseCoverageTable reads the pinned flag", () => {
const { rows } = parseCoverageTable(DOC);
assert.equal(rows[0].pinned, false);
assert.equal(rows[3].pinned, true);
});
test("parseCoverageTable strips a wikilink alias", () => {
const doc = "| Concept | Status | Station |\n|---|---|---|\n| [[harness\\|The harness]] | covered | Tools |";
const { rows } = parseCoverageTable(doc);
assert.equal(rows[0].concept, "harness");
});
test("parseCoverageTable splits a multi-station cell", () => {
const doc = "| C | S | St |\n|---|---|---|\n| [[x]] | covered | Tools, Memory |";
const { rows } = parseCoverageTable(doc);
assert.deepEqual(rows[0].stations, ["Tools", "Memory"]);
});
test("parseCoverageTable rejects an invalid status instead of coercing it", () => {
const doc = "| C | S | St |\n|---|---|---|\n| [[x]] | maybe | Tools |";
const { rows, errors } = parseCoverageTable(doc);
assert.equal(rows.length, 0);
assert.equal(errors.length, 1);
assert.match(errors[0].reason, /invalid status/);
assert.equal(errors[0].line, 3);
});
test("parseCoverageTable reports a row with too few columns", () => {
const doc = "| C | S | St |\n|---|---|---|\n| [[x]] | covered |";
const { rows, errors } = parseCoverageTable(doc);
assert.equal(rows.length, 0);
assert.equal(errors.length, 1);
assert.match(errors[0].reason, /at least 3 columns/);
});
test("parseCoverageTable returns empty results for a document with no table", () => {
const { rows, errors } = parseCoverageTable("# Nothing\n\nJust prose.");
assert.equal(rows.length, 0);
assert.equal(errors.length, 0);
});
test("groupByStation orders all-stations first and no-station last", () => {
const { rows } = parseCoverageTable(DOC);
const groups = groupByStation(rows);
assert.deepEqual(groups.map((g) => g.station), [
"All stations", "Tools", "Process", "No station",
]);
assert.equal(groups[1].rows[0].concept, "harness");
});
test("groupByStation places a multi-station row under its first station only", () => {
const rows = [{ concept: "x", status: "covered", stations: ["Memory", "Skills"], pinned: false, line: 1 }];
const groups = groupByStation(rows);
assert.equal(groups.length, 1);
assert.equal(groups[0].station, "Memory");
});
const { reconcileConcepts } = require("../main.js").__test__;
test("reconcileConcepts finds concept pages with no row", () => {
const rows = [{ concept: "harness", status: "covered", stations: ["Tools"], pinned: false, line: 1 }];
const out = reconcileConcepts(rows, ["harness", "brand-new-concept"]);
assert.deepEqual(out.unsynced, ["brand-new-concept"]);
assert.deepEqual(out.stale, []);
});
test("reconcileConcepts finds rows whose concept page is gone", () => {
const rows = [
{ concept: "harness", status: "covered", stations: ["Tools"], pinned: false, line: 1 },
{ concept: "deleted-idea", status: "absent", stations: [], pinned: false, line: 2 },
];
const out = reconcileConcepts(rows, ["harness"]);
assert.deepEqual(out.stale.map((r) => r.concept), ["deleted-idea"]);
assert.deepEqual(out.unsynced, []);
});
"use strict";
const test = require("node:test");
const assert = require("node:assert/strict");
const { parseCoverageTable, groupByStation } = require("../main.js").__test__;
const DOC = [
"# Script coverage",
"",
"#coverage",
"",
"## Metadata",
"",
"- **Script:** `raw/sources/Webinar script.md`",
"- **Last synced:** 2026-07-28",
"",
"## Coverage",
"",
"| Concept | Status | Station | Pinned |",
"|---|---|---|---|",
"| [[harness]] | covered | Tools | |",
"| [[agentic-loops]] | partial | Process | |",
"| [[levels-of-ai-usage]] | partial | all | |",
"| [[connections-as-moat]] | absent | — | yes |",
].join("\n");
test("parseCoverageTable reads metadata", () => {
const { meta } = parseCoverageTable(DOC);
assert.equal(meta.script, "raw/sources/Webinar script.md");
assert.equal(meta.lastSynced, "2026-07-28");
});
test("parseCoverageTable reads every data row and skips the header", () => {
const { rows, errors } = parseCoverageTable(DOC);
assert.equal(errors.length, 0);
assert.equal(rows.length, 4);
assert.deepEqual(rows.map((r) => r.concept), [
"harness", "agentic-loops", "levels-of-ai-usage", "connections-as-moat",
]);
});
test("parseCoverageTable normalises stations", () => {
const { rows } = parseCoverageTable(DOC);
assert.deepEqual(rows[0].stations, ["Tools"]);
assert.deepEqual(rows[2].stations, ["all"]);
assert.deepEqual(rows[3].stations, []);
});
test("parseCoverageTable reads the pinned flag", () => {
const { rows } = parseCoverageTable(DOC);
assert.equal(rows[0].pinned, false);
assert.equal(rows[3].pinned, true);
});
test("parseCoverageTable strips a wikilink alias", () => {
const doc = "| Concept | Status | Station |\n|---|---|---|\n| [[harness\\|The harness]] | covered | Tools |";
const { rows } = parseCoverageTable(doc);
assert.equal(rows[0].concept, "harness");
});
test("parseCoverageTable splits a multi-station cell", () => {
const doc = "| C | S | St |\n|---|---|---|\n| [[x]] | covered | Tools, Memory |";
const { rows } = parseCoverageTable(doc);
assert.deepEqual(rows[0].stations, ["Tools", "Memory"]);
});
test("parseCoverageTable rejects an invalid status instead of coercing it", () => {
const doc = "| C | S | St |\n|---|---|---|\n| [[x]] | maybe | Tools |";
const { rows, errors } = parseCoverageTable(doc);
assert.equal(rows.length, 0);
assert.equal(errors.length, 1);
assert.match(errors[0].reason, /invalid status/);
assert.equal(errors[0].line, 3);
});
test("parseCoverageTable reports a row with too few columns", () => {
const doc = "| C | S | St |\n|---|---|---|\n| [[x]] | covered |";
const { rows, errors } = parseCoverageTable(doc);
assert.equal(rows.length, 0);
assert.equal(errors.length, 1);
assert.match(errors[0].reason, /at least 3 columns/);
});
test("parseCoverageTable returns empty results for a document with no table", () => {
const { rows, errors } = parseCoverageTable("# Nothing\n\nJust prose.");
assert.equal(rows.length, 0);
assert.equal(errors.length, 0);
});
test("groupByStation orders all-stations first and no-station last", () => {
const { rows } = parseCoverageTable(DOC);
const groups = groupByStation(rows);
assert.deepEqual(groups.map((g) => g.station), [
"All stations", "Tools", "Process", "No station",
]);
assert.equal(groups[1].rows[0].concept, "harness");
});
test("groupByStation places a multi-station row under its first station only", () => {
const rows = [{ concept: "x", status: "covered", stations: ["Memory", "Skills"], pinned: false, line: 1 }];
const groups = groupByStation(rows);
assert.equal(groups.length, 1);
assert.equal(groups[0].station, "Memory");
});
const { reconcileConcepts } = require("../main.js").__test__;
test("reconcileConcepts finds concept pages with no row", () => {
const rows = [{ concept: "harness", status: "covered", stations: ["Tools"], pinned: false, line: 1 }];
const out = reconcileConcepts(rows, ["harness", "brand-new-concept"]);
assert.deepEqual(out.unsynced, ["brand-new-concept"]);
assert.deepEqual(out.stale, []);
});
test("reconcileConcepts finds rows whose concept page is gone", () => {
const rows = [
{ concept: "harness", status: "covered", stations: ["Tools"], pinned: false, line: 1 },
{ concept: "deleted-idea", status: "absent", stations: [], pinned: false, line: 2 },
];
const out = reconcileConcepts(rows, ["harness"]);
assert.deepEqual(out.stale.map((r) => r.concept), ["deleted-idea"]);
assert.deepEqual(out.unsynced, []);
});

View File

@@ -1,109 +1,109 @@
"use strict";
const test = require("node:test");
const assert = require("node:assert/strict");
const { extractRawPath, derivePipeline } = require("../main.js").__test__;
test("extractRawPath pulls the backticked path", () => {
const page = [
"# You're reading way too much code",
"",
"#source",
"",
"## Source Metadata",
"",
"- **Date:** YouTube video, 24:11",
"- **Raw path:** `raw/sources/You're reading way too much code.md`",
"- **Source type:** video essay",
].join("\n");
assert.equal(extractRawPath(page), "raw/sources/You're reading way too much code.md");
});
test("extractRawPath handles cyrillic and em dashes", () => {
const page = "- **Raw path:** `raw/sources/Скиллы на базе git — новая память AI-агентов.md`";
assert.equal(extractRawPath(page), "raw/sources/Скиллы на базе git — новая память AI-агентов.md");
});
test("extractRawPath returns null when the line is absent", () => {
assert.equal(extractRawPath("# A page\n\n#source\n\nNo metadata here."), null);
});
test("derivePipeline splits claimed from unclaimed raw files", () => {
const rawFiles = [
{ path: "raw/sources/Nina interview.md", name: "Nina interview.md", size: 6614 },
{ path: "raw/sources/Webinar script.md", name: "Webinar script.md", size: 15841 },
];
const sourcePages = [
{
path: "wiki/sources/2026-07-14-nina-interview.md",
name: "2026-07-14-nina-interview.md",
rawPath: "raw/sources/Nina interview.md",
},
];
const out = derivePipeline({ rawFiles, sourcePages });
assert.equal(out.processed.length, 1);
assert.equal(out.processed[0].name, "Nina interview.md");
assert.equal(out.processed[0].page.name, "2026-07-14-nina-interview.md");
assert.equal(out.unprocessed.length, 1);
assert.equal(out.unprocessed[0].name, "Webinar script.md");
assert.equal(out.orphaned.length, 0);
});
test("derivePipeline reports source pages whose raw file is gone", () => {
const out = derivePipeline({
rawFiles: [],
sourcePages: [
{ path: "wiki/sources/x.md", name: "x.md", rawPath: "raw/sources/deleted.md" },
],
});
assert.equal(out.orphaned.length, 1);
assert.equal(out.orphaned[0].name, "x.md");
});
test("derivePipeline treats a page with no raw path as orphaned", () => {
const out = derivePipeline({
rawFiles: [{ path: "raw/sources/a.md", name: "a.md", size: 10 }],
sourcePages: [{ path: "wiki/sources/y.md", name: "y.md", rawPath: null }],
});
assert.equal(out.orphaned.length, 1);
assert.equal(out.unprocessed.length, 1);
});
test("derivePipeline routes a duplicate raw-path claim to orphaned", () => {
const out = derivePipeline({
rawFiles: [{ path: "raw/sources/a.md", name: "a.md", size: 10 }],
sourcePages: [
{ path: "wiki/sources/first.md", name: "first.md", rawPath: "raw/sources/a.md" },
{ path: "wiki/sources/second.md", name: "second.md", rawPath: "raw/sources/a.md" },
],
});
assert.equal(out.processed.length, 1);
assert.equal(out.processed[0].page.name, "first.md");
assert.equal(out.unprocessed.length, 0);
assert.deepEqual(out.orphaned.map((p) => p.name), ["second.md"]);
});
test("derivePipeline lists a page once when it is both a duplicate claim and missing its raw file", () => {
const out = derivePipeline({
rawFiles: [{ path: "raw/sources/other.md", name: "other.md", size: 10 }],
sourcePages: [
{ path: "wiki/sources/first.md", name: "first.md", rawPath: "raw/sources/gone.md" },
{ path: "wiki/sources/second.md", name: "second.md", rawPath: "raw/sources/gone.md" },
],
});
assert.deepEqual(out.orphaned.map((p) => p.name), ["first.md", "second.md"]);
});
test("derivePipeline sorts unprocessed by name and processed newest first", () => {
const out = derivePipeline({
rawFiles: [
{ path: "raw/sources/b.md", name: "b.md", size: 1 },
{ path: "raw/sources/a.md", name: "a.md", size: 1 },
{ path: "raw/sources/c.md", name: "c.md", size: 1 },
],
sourcePages: [
{ path: "wiki/sources/2026-07-14-x.md", name: "2026-07-14-x.md", rawPath: "raw/sources/c.md" },
],
});
assert.deepEqual(out.unprocessed.map((f) => f.name), ["a.md", "b.md"]);
assert.equal(out.processed.length, 1);
});
"use strict";
const test = require("node:test");
const assert = require("node:assert/strict");
const { extractRawPath, derivePipeline } = require("../main.js").__test__;
test("extractRawPath pulls the backticked path", () => {
const page = [
"# You're reading way too much code",
"",
"#source",
"",
"## Source Metadata",
"",
"- **Date:** YouTube video, 24:11",
"- **Raw path:** `raw/sources/You're reading way too much code.md`",
"- **Source type:** video essay",
].join("\n");
assert.equal(extractRawPath(page), "raw/sources/You're reading way too much code.md");
});
test("extractRawPath handles cyrillic and em dashes", () => {
const page = "- **Raw path:** `raw/sources/Скиллы на базе git — новая память AI-агентов.md`";
assert.equal(extractRawPath(page), "raw/sources/Скиллы на базе git — новая память AI-агентов.md");
});
test("extractRawPath returns null when the line is absent", () => {
assert.equal(extractRawPath("# A page\n\n#source\n\nNo metadata here."), null);
});
test("derivePipeline splits claimed from unclaimed raw files", () => {
const rawFiles = [
{ path: "raw/sources/Nina interview.md", name: "Nina interview.md", size: 6614 },
{ path: "raw/sources/Webinar script.md", name: "Webinar script.md", size: 15841 },
];
const sourcePages = [
{
path: "wiki/sources/2026-07-14-nina-interview.md",
name: "2026-07-14-nina-interview.md",
rawPath: "raw/sources/Nina interview.md",
},
];
const out = derivePipeline({ rawFiles, sourcePages });
assert.equal(out.processed.length, 1);
assert.equal(out.processed[0].name, "Nina interview.md");
assert.equal(out.processed[0].page.name, "2026-07-14-nina-interview.md");
assert.equal(out.unprocessed.length, 1);
assert.equal(out.unprocessed[0].name, "Webinar script.md");
assert.equal(out.orphaned.length, 0);
});
test("derivePipeline reports source pages whose raw file is gone", () => {
const out = derivePipeline({
rawFiles: [],
sourcePages: [
{ path: "wiki/sources/x.md", name: "x.md", rawPath: "raw/sources/deleted.md" },
],
});
assert.equal(out.orphaned.length, 1);
assert.equal(out.orphaned[0].name, "x.md");
});
test("derivePipeline treats a page with no raw path as orphaned", () => {
const out = derivePipeline({
rawFiles: [{ path: "raw/sources/a.md", name: "a.md", size: 10 }],
sourcePages: [{ path: "wiki/sources/y.md", name: "y.md", rawPath: null }],
});
assert.equal(out.orphaned.length, 1);
assert.equal(out.unprocessed.length, 1);
});
test("derivePipeline routes a duplicate raw-path claim to orphaned", () => {
const out = derivePipeline({
rawFiles: [{ path: "raw/sources/a.md", name: "a.md", size: 10 }],
sourcePages: [
{ path: "wiki/sources/first.md", name: "first.md", rawPath: "raw/sources/a.md" },
{ path: "wiki/sources/second.md", name: "second.md", rawPath: "raw/sources/a.md" },
],
});
assert.equal(out.processed.length, 1);
assert.equal(out.processed[0].page.name, "first.md");
assert.equal(out.unprocessed.length, 0);
assert.deepEqual(out.orphaned.map((p) => p.name), ["second.md"]);
});
test("derivePipeline lists a page once when it is both a duplicate claim and missing its raw file", () => {
const out = derivePipeline({
rawFiles: [{ path: "raw/sources/other.md", name: "other.md", size: 10 }],
sourcePages: [
{ path: "wiki/sources/first.md", name: "first.md", rawPath: "raw/sources/gone.md" },
{ path: "wiki/sources/second.md", name: "second.md", rawPath: "raw/sources/gone.md" },
],
});
assert.deepEqual(out.orphaned.map((p) => p.name), ["first.md", "second.md"]);
});
test("derivePipeline sorts unprocessed by name and processed newest first", () => {
const out = derivePipeline({
rawFiles: [
{ path: "raw/sources/b.md", name: "b.md", size: 1 },
{ path: "raw/sources/a.md", name: "a.md", size: 1 },
{ path: "raw/sources/c.md", name: "c.md", size: 1 },
],
sourcePages: [
{ path: "wiki/sources/2026-07-14-x.md", name: "2026-07-14-x.md", rawPath: "raw/sources/c.md" },
],
});
assert.deepEqual(out.unprocessed.map((f) => f.name), ["a.md", "b.md"]);
assert.equal(out.processed.length, 1);
});

View File

@@ -1,47 +1,47 @@
"use strict";
const test = require("node:test");
const assert = require("node:assert/strict");
const { isSafeFilename } = require("../main.js").__test__;
test("isSafeFilename accepts every filename currently in the vault", () => {
const real = [
"Agentic Engineering, explained by a 10x developer.md",
"Webinar Plan - From Chat Box to Your Own OS.md",
"Webinar script.md",
"You're reading way too much code.md",
"ИИ глупый!.md",
"Скиллы на базе git — новая память AI-агентов.md",
"sebastian interview - conclusions and insights.md",
"In 1 Year, the Gap Between AI Users and Everyone Else Will Be Irreversible.md",
];
for (const name of real) {
assert.equal(isSafeFilename(name), true, `should accept: ${name}`);
}
});
test("isSafeFilename rejects shell metacharacters", () => {
for (const bad of ['a".md', "a`b.md", "a$b.md", "a&b.md", "a|b.md", "a;b.md",
"a<b.md", "a>b.md", "a%b.md", "a\nb.md", "a\rb.md"]) {
assert.equal(isSafeFilename(bad), false, `should reject: ${JSON.stringify(bad)}`);
}
});
test("isSafeFilename rejects the cmd.exe escape character and control characters", () => {
// `^` escapes the next character in cmd.exe, so it can defuse the closing
// quote. NUL additionally makes spawn() throw synchronously.
for (const bad of ["a^b.md", "a\u0000b.md", "a\u001bb.md", "a\u007fb.md"]) {
assert.equal(isSafeFilename(bad), false, `should reject: ${JSON.stringify(bad)}`);
}
});
test("isSafeFilename rejects path traversal", () => {
assert.equal(isSafeFilename("../secrets.md"), false);
assert.equal(isSafeFilename("a/../../b.md"), false);
});
test("isSafeFilename rejects empty and non-string input", () => {
assert.equal(isSafeFilename(""), false);
assert.equal(isSafeFilename(null), false);
assert.equal(isSafeFilename(undefined), false);
assert.equal(isSafeFilename(42), false);
});
"use strict";
const test = require("node:test");
const assert = require("node:assert/strict");
const { isSafeFilename } = require("../main.js").__test__;
test("isSafeFilename accepts every filename currently in the vault", () => {
const real = [
"Agentic Engineering, explained by a 10x developer.md",
"Webinar Plan - From Chat Box to Your Own OS.md",
"Webinar script.md",
"You're reading way too much code.md",
"ИИ глупый!.md",
"Скиллы на базе git — новая память AI-агентов.md",
"sebastian interview - conclusions and insights.md",
"In 1 Year, the Gap Between AI Users and Everyone Else Will Be Irreversible.md",
];
for (const name of real) {
assert.equal(isSafeFilename(name), true, `should accept: ${name}`);
}
});
test("isSafeFilename rejects shell metacharacters", () => {
for (const bad of ['a".md', "a`b.md", "a$b.md", "a&b.md", "a|b.md", "a;b.md",
"a<b.md", "a>b.md", "a%b.md", "a\nb.md", "a\rb.md"]) {
assert.equal(isSafeFilename(bad), false, `should reject: ${JSON.stringify(bad)}`);
}
});
test("isSafeFilename rejects the cmd.exe escape character and control characters", () => {
// `^` escapes the next character in cmd.exe, so it can defuse the closing
// quote. NUL additionally makes spawn() throw synchronously.
for (const bad of ["a^b.md", "a\u0000b.md", "a\u001bb.md", "a\u007fb.md"]) {
assert.equal(isSafeFilename(bad), false, `should reject: ${JSON.stringify(bad)}`);
}
});
test("isSafeFilename rejects path traversal", () => {
assert.equal(isSafeFilename("../secrets.md"), false);
assert.equal(isSafeFilename("a/../../b.md"), false);
});
test("isSafeFilename rejects empty and non-string input", () => {
assert.equal(isSafeFilename(""), false);
assert.equal(isSafeFilename(null), false);
assert.equal(isSafeFilename(undefined), false);
assert.equal(isSafeFilename(42), false);
});

496
CLAUDE.md
View File

@@ -1,248 +1,248 @@
# LLM Wiki Schema (Operational Contract)
You are the dedicated maintainer of this vault as a persistent, compounding wiki.
## Mission
Maintain a high-signal personal knowledge base where:
- `raw/` contains immutable source materials.
- `wiki/` contains LLM-authored, continuously maintained markdown pages.
- `index.md` is the content catalog.
- `log.md` is an append-only chronological operation log.
The user curates sources and asks questions. You perform all wiki maintenance.
## Non-Negotiable Rules
1. Never modify files inside `raw/`.
2. Always update `index.md` and `log.md` after any ingest/query/lint operation that changes the wiki.
3. Prefer editing existing pages over creating duplicates.
4. Use Obsidian-style wiki links (`[[page-name]]`) for internal references.
5. Record contradictions and superseded claims explicitly (do not silently overwrite history).
6. Keep claims attributable: include source links to `wiki/sources/*` pages.
7. Do not leave orphan pages intentionally; add at least one inbound and one outbound link when possible.
8. Keep writing concise, structured, and diff-friendly.
9. Every wiki page carries exactly one page-type hashtag (see Tagging Rules) matching its folder.
## Folder Convention
```text
raw/
sources/ # immutable source markdown/text/pdf exports
assets/ # immutable local images/files referenced by raw sources
wiki/
overview.md # top-level synthesis and navigation
script-coverage.md # machine-maintained: concept coverage vs the webinar script
sources/ # one summary page per ingested raw source
entities/ # people, orgs, projects, places, tools
concepts/ # themes, ideas, methods, frameworks
timelines/ # optional chronological reconstructions
comparisons/ # side-by-side analyses
queries/ # durable outputs created from Q&A sessions
lint-reports/ # periodic health-check reports
```
## File Naming Rules
- Use kebab-case for file names.
- Prefix source summary pages with date: `YYYY-MM-DD-title.md`.
- Prefer stable canonical pages:
- `wiki/entities/<name>.md`
- `wiki/concepts/<concept>.md`
- If a page name collides, merge instead of creating suffixes unless truly distinct.
## Tagging Rules
Every page in `wiki/` starts with its page-type hashtag on its own line, directly after the `# <title>` heading (Obsidian inline tag format):
```text
# <Title>
#<type-tag>
## <first section>
```
Folder → required tag:
| Folder / file | Tag |
| ---------------------- | -------------- |
| `wiki/overview.md` | `#overview` |
| `wiki/script-coverage.md` | `#coverage` |
| `wiki/sources/*` | `#source` |
| `wiki/entities/*` | `#entity` |
| `wiki/concepts/*` | `#concept` |
| `wiki/timelines/*` | `#timeline` |
| `wiki/comparisons/*` | `#comparison` |
| `wiki/queries/*` | `#query` |
| `wiki/lint-reports/*` | `#lint-report` |
- Exactly one page-type tag per page; it must match the page's folder.
- Additional topical tags are allowed on the same line after the type tag (e.g. `#concept #ai-tooling`), but the type tag comes first.
- When creating any new page, add the tag immediately; when moving a page between folders, update the tag in the same operation.
## Required Page Templates
### 1) Source Summary (`wiki/sources/*.md`)
Must include sections:
- `# <title>`
- `#source` tag line (per Tagging Rules)
- `## Source Metadata` (date, raw path, source type, ingestion date)
- `## Core Claims`
- `## Key Evidence / Details`
- `## Connections` (links to entities/concepts/comparisons)
- `## Open Questions`
- `## Change Impact on Wiki` (what pages were updated and why)
### 2) Entity / Concept Page
Must include:
- `# <name>`
- `#entity` or `#concept` tag line (per Tagging Rules)
- `## Summary`
- `## Current Understanding`
- `## Evidence` (bullets with links to `wiki/sources/*`)
- `## Related Pages`
- `## Contradictions / Uncertainty`
- `## Next Questions`
### 3) Query Output (`wiki/queries/*.md`)
Must include:
- `#query` tag line (per Tagging Rules)
- Question asked
- Answer
- Evidence trail (links)
- Follow-up questions
- Whether this output changed existing pages
### 4) Coverage File (`wiki/script-coverage.md`)
Machine-read by the dashboard plugin, which parses the table positionally. The
shape below is required exactly — a deviation renders as parse errors, not as a
best-effort read.
- `# Script coverage`
- `#coverage` tag line
- `## Metadata`, containing these two lines verbatim in this form:
- `- **Script:** ` followed by the raw script path in backticks
- `- **Last synced:** ` followed by a `YYYY-MM-DD` date
- `## Coverage`, containing one markdown table with exactly these four columns in
this order: `Concept`, `Status`, `Station`, `Pinned`
- **Concept** — an Obsidian wikilink to a page in `wiki/concepts/`
- **Status** — exactly one of `covered`, `partial`, `absent`, lowercase
- **Station** — one of the seven station names spelled exactly as listed in
Workflow D, a comma-separated list of them, the lowercase word `all`, or an
em dash `—` when the status is `absent`
- **Pinned** — the lowercase word `yes`, or empty
- `## Notes` and `## Related Pages` are free prose and are not parsed.
The parser reads every markdown table in the file, so do not add a second table.
## Standard Workflows
### Workflow A: Ingest One Source
When user says "ingest <source>":
1. Read the raw source from `raw/sources/` (and `raw/assets/` references if needed).
2. Extract key claims, facts, entities, concepts, uncertainty.
3. Create/update one source summary in `wiki/sources/`.
4. Update relevant `wiki/entities/*` and `wiki/concepts/*` pages.
5. Update `wiki/overview.md` synthesis if this source materially changes understanding.
6. Update `index.md`.
7. Append ingest entry to `log.md`.
8. Report what changed, what is uncertain, and suggested next source/questions.
9. If this ingest created or modified any page in `wiki/concepts/`, run Workflow D
(Sync Script Coverage) before reporting.
### Workflow B: Answer Query
1. Read `index.md` first.
2. Select relevant pages and synthesize answer with page citations.
3. If answer has durable value, save to `wiki/queries/YYYY-MM-DD-<slug>.md`.
4. If answer reveals new synthesis, update affected concept/entity pages.
5. Update `index.md` and append query entry in `log.md` when files changed.
### Workflow C: Lint Wiki
Run periodic health checks for:
- contradiction detection across pages
- stale claims superseded by newer sources
- orphan pages / weak linking
- high-mention concepts lacking dedicated pages
- missing evidence links
- missing or folder-mismatched page-type tags (per Tagging Rules)
Write report to `wiki/lint-reports/YYYY-MM-DD-lint.md`, then update `index.md` and `log.md`.
### Workflow D: Sync Script Coverage
Maintains `wiki/script-coverage.md` — one row per page in `wiki/concepts/`, judged
against the script named in that file's `**Script:**` metadata field.
1. Read `wiki/script-coverage.md` and note every row where `Pinned` is `yes`.
2. Read the script and every page in `wiki/concepts/`.
3. For each concept, decide `Status` and `Station`:
- `covered` — the script delivers the idea, whether or not it uses the page's name.
- `partial` — the script gestures at it but never lands it.
- `absent` — the script never reaches it.
- `Station` is one of the seven — `Chat box`, `ReAct`, `Tools`, `Memory`,
`Skills`, `Process`, `OS` — spelled exactly as written here, or a
comma-separated list of them, or the lowercase word `all`, or `—` when absent.
4. **Never modify a row whose `Pinned` is `yes`** — not its status, not its station.
A pinned row is the user's judgment and outranks yours.
5. Add rows for concept pages with no row. Remove rows whose concept page no longer exists.
A pinned row whose concept page no longer exists is still removed — step 4
protects the user's judgement about a live concept, not a dangling row.
6. Update `**Last synced:**` to today.
7. Update `index.md` and append a `sync` entry to `log.md`.
Run this workflow:
- at the end of any ingest that creates or modifies a page in `wiki/concepts/`
- whenever the script file itself changes
- on the explicit `sync script coverage` intent
The coverage baseline is always the raw script. Ingesting the script into
`wiki/sources/` does not change the baseline.
## Citation & Evidence Policy
- Prefer citing wiki source summaries (`wiki/sources/*.md`) rather than raw files in normal answers.
- If citing raw material directly, also reflect it into a source summary page.
- Mark uncertain or contested claims with `Status: tentative` in relevant section.
## Update Policy
- Never perform silent large rewrites.
- Preserve meaningful prior interpretations; move outdated material under a "Superseded" note when needed.
- Keep sections ordered consistently for predictable diffs.
## Operational Commands (Natural Language)
Supported intents:
- "ingest path-or-title"
- "query: question"
- "lint wiki"
- "show recent changes"
- "suggest next sources"
- "sync script coverage"
Always execute intents according to workflows above.
## Session Start Checklist
At start of every session:
1. Read `index.md` and the latest section of `log.md`.
2. Identify last completed operation and current open questions.
3. Continue from prior state without resetting conventions.
# LLM Wiki Schema (Operational Contract)
You are the dedicated maintainer of this vault as a persistent, compounding wiki.
## Mission
Maintain a high-signal personal knowledge base where:
- `raw/` contains immutable source materials.
- `wiki/` contains LLM-authored, continuously maintained markdown pages.
- `index.md` is the content catalog.
- `log.md` is an append-only chronological operation log.
The user curates sources and asks questions. You perform all wiki maintenance.
## Non-Negotiable Rules
1. Never modify files inside `raw/`.
2. Always update `index.md` and `log.md` after any ingest/query/lint operation that changes the wiki.
3. Prefer editing existing pages over creating duplicates.
4. Use Obsidian-style wiki links (`[[page-name]]`) for internal references.
5. Record contradictions and superseded claims explicitly (do not silently overwrite history).
6. Keep claims attributable: include source links to `wiki/sources/*` pages.
7. Do not leave orphan pages intentionally; add at least one inbound and one outbound link when possible.
8. Keep writing concise, structured, and diff-friendly.
9. Every wiki page carries exactly one page-type hashtag (see Tagging Rules) matching its folder.
## Folder Convention
```text
raw/
sources/ # immutable source markdown/text/pdf exports
assets/ # immutable local images/files referenced by raw sources
wiki/
overview.md # top-level synthesis and navigation
script-coverage.md # machine-maintained: concept coverage vs the webinar script
sources/ # one summary page per ingested raw source
entities/ # people, orgs, projects, places, tools
concepts/ # themes, ideas, methods, frameworks
timelines/ # optional chronological reconstructions
comparisons/ # side-by-side analyses
queries/ # durable outputs created from Q&A sessions
lint-reports/ # periodic health-check reports
```
## File Naming Rules
- Use kebab-case for file names.
- Prefix source summary pages with date: `YYYY-MM-DD-title.md`.
- Prefer stable canonical pages:
- `wiki/entities/<name>.md`
- `wiki/concepts/<concept>.md`
- If a page name collides, merge instead of creating suffixes unless truly distinct.
## Tagging Rules
Every page in `wiki/` starts with its page-type hashtag on its own line, directly after the `# <title>` heading (Obsidian inline tag format):
```text
# <Title>
#<type-tag>
## <first section>
```
Folder → required tag:
| Folder / file | Tag |
| ---------------------- | -------------- |
| `wiki/overview.md` | `#overview` |
| `wiki/script-coverage.md` | `#coverage` |
| `wiki/sources/*` | `#source` |
| `wiki/entities/*` | `#entity` |
| `wiki/concepts/*` | `#concept` |
| `wiki/timelines/*` | `#timeline` |
| `wiki/comparisons/*` | `#comparison` |
| `wiki/queries/*` | `#query` |
| `wiki/lint-reports/*` | `#lint-report` |
- Exactly one page-type tag per page; it must match the page's folder.
- Additional topical tags are allowed on the same line after the type tag (e.g. `#concept #ai-tooling`), but the type tag comes first.
- When creating any new page, add the tag immediately; when moving a page between folders, update the tag in the same operation.
## Required Page Templates
### 1) Source Summary (`wiki/sources/*.md`)
Must include sections:
- `# <title>`
- `#source` tag line (per Tagging Rules)
- `## Source Metadata` (date, raw path, source type, ingestion date)
- `## Core Claims`
- `## Key Evidence / Details`
- `## Connections` (links to entities/concepts/comparisons)
- `## Open Questions`
- `## Change Impact on Wiki` (what pages were updated and why)
### 2) Entity / Concept Page
Must include:
- `# <name>`
- `#entity` or `#concept` tag line (per Tagging Rules)
- `## Summary`
- `## Current Understanding`
- `## Evidence` (bullets with links to `wiki/sources/*`)
- `## Related Pages`
- `## Contradictions / Uncertainty`
- `## Next Questions`
### 3) Query Output (`wiki/queries/*.md`)
Must include:
- `#query` tag line (per Tagging Rules)
- Question asked
- Answer
- Evidence trail (links)
- Follow-up questions
- Whether this output changed existing pages
### 4) Coverage File (`wiki/script-coverage.md`)
Machine-read by the dashboard plugin, which parses the table positionally. The
shape below is required exactly — a deviation renders as parse errors, not as a
best-effort read.
- `# Script coverage`
- `#coverage` tag line
- `## Metadata`, containing these two lines verbatim in this form:
- `- **Script:** ` followed by the raw script path in backticks
- `- **Last synced:** ` followed by a `YYYY-MM-DD` date
- `## Coverage`, containing one markdown table with exactly these four columns in
this order: `Concept`, `Status`, `Station`, `Pinned`
- **Concept** — an Obsidian wikilink to a page in `wiki/concepts/`
- **Status** — exactly one of `covered`, `partial`, `absent`, lowercase
- **Station** — one of the seven station names spelled exactly as listed in
Workflow D, a comma-separated list of them, the lowercase word `all`, or an
em dash `—` when the status is `absent`
- **Pinned** — the lowercase word `yes`, or empty
- `## Notes` and `## Related Pages` are free prose and are not parsed.
The parser reads every markdown table in the file, so do not add a second table.
## Standard Workflows
### Workflow A: Ingest One Source
When user says "ingest <source>":
1. Read the raw source from `raw/sources/` (and `raw/assets/` references if needed).
2. Extract key claims, facts, entities, concepts, uncertainty.
3. Create/update one source summary in `wiki/sources/`.
4. Update relevant `wiki/entities/*` and `wiki/concepts/*` pages.
5. Update `wiki/overview.md` synthesis if this source materially changes understanding.
6. Update `index.md`.
7. Append ingest entry to `log.md`.
8. Report what changed, what is uncertain, and suggested next source/questions.
9. If this ingest created or modified any page in `wiki/concepts/`, run Workflow D
(Sync Script Coverage) before reporting.
### Workflow B: Answer Query
1. Read `index.md` first.
2. Select relevant pages and synthesize answer with page citations.
3. If answer has durable value, save to `wiki/queries/YYYY-MM-DD-<slug>.md`.
4. If answer reveals new synthesis, update affected concept/entity pages.
5. Update `index.md` and append query entry in `log.md` when files changed.
### Workflow C: Lint Wiki
Run periodic health checks for:
- contradiction detection across pages
- stale claims superseded by newer sources
- orphan pages / weak linking
- high-mention concepts lacking dedicated pages
- missing evidence links
- missing or folder-mismatched page-type tags (per Tagging Rules)
Write report to `wiki/lint-reports/YYYY-MM-DD-lint.md`, then update `index.md` and `log.md`.
### Workflow D: Sync Script Coverage
Maintains `wiki/script-coverage.md` — one row per page in `wiki/concepts/`, judged
against the script named in that file's `**Script:**` metadata field.
1. Read `wiki/script-coverage.md` and note every row where `Pinned` is `yes`.
2. Read the script and every page in `wiki/concepts/`.
3. For each concept, decide `Status` and `Station`:
- `covered` — the script delivers the idea, whether or not it uses the page's name.
- `partial` — the script gestures at it but never lands it.
- `absent` — the script never reaches it.
- `Station` is one of the seven — `Chat box`, `ReAct`, `Tools`, `Memory`,
`Skills`, `Process`, `OS` — spelled exactly as written here, or a
comma-separated list of them, or the lowercase word `all`, or `—` when absent.
4. **Never modify a row whose `Pinned` is `yes`** — not its status, not its station.
A pinned row is the user's judgment and outranks yours.
5. Add rows for concept pages with no row. Remove rows whose concept page no longer exists.
A pinned row whose concept page no longer exists is still removed — step 4
protects the user's judgement about a live concept, not a dangling row.
6. Update `**Last synced:**` to today.
7. Update `index.md` and append a `sync` entry to `log.md`.
Run this workflow:
- at the end of any ingest that creates or modifies a page in `wiki/concepts/`
- whenever the script file itself changes
- on the explicit `sync script coverage` intent
The coverage baseline is always the raw script. Ingesting the script into
`wiki/sources/` does not change the baseline.
## Citation & Evidence Policy
- Prefer citing wiki source summaries (`wiki/sources/*.md`) rather than raw files in normal answers.
- If citing raw material directly, also reflect it into a source summary page.
- Mark uncertain or contested claims with `Status: tentative` in relevant section.
## Update Policy
- Never perform silent large rewrites.
- Preserve meaningful prior interpretations; move outdated material under a "Superseded" note when needed.
- Keep sections ordered consistently for predictable diffs.
## Operational Commands (Natural Language)
Supported intents:
- "ingest path-or-title"
- "query: question"
- "lint wiki"
- "show recent changes"
- "suggest next sources"
- "sync script coverage"
Always execute intents according to workflows above.
## Session Start Checklist
At start of every session:
1. Read `index.md` and the latest section of `log.md`.
2. Identify last completed operation and current open questions.
3. Continue from prior state without resetting conventions.

File diff suppressed because it is too large Load Diff

View File

@@ -1,256 +1,256 @@
# Webinar vault dashboard — design
Date: 2026-07-28
Status: approved, ready for implementation planning
## Context
The vault is an LLM-maintained wiki governed by `CLAUDE.md`. It currently holds 12 raw
sources, 9 ingested source summaries, 19 concept pages, and one webinar script
(`raw/sources/Webinar script.md`) that the concepts are supposed to feed.
Two problems motivated this work:
1. **The manual catalog drifts.** `index.md` lists `Ideas for webinar.md` and
`my theses.md` under `raw/sources/`, but both live in `raw/notes/`. It does not
mention `Agentic Engineering, explained by a 10x developer.md` at all, which sits
un-ingested in `raw/sources/`. Nothing detects this.
2. **No view of script coverage.** There is no way to see which concept pages the
webinar script actually delivers. A manual read shows the script is entirely
machine-side: all human-side and strategy-side concepts are absent.
## Goals
- Show processed and unprocessed sources, with a one-click ingest on the unprocessed.
- Show every concept and whether the webinar script mentions it, plus which script
station it lands in.
- Keep coverage status in a separate markdown file, kept synchronized by a rule in
`CLAUDE.md`.
## Non-goals
- Replacing `index.md` or `log.md`. Both stay exactly as they are.
- A general-purpose Obsidian dashboard framework. This is one vault-specific plugin.
- Publishing the plugin to the community plugin registry.
## Decisions taken
| Decision | Choice | Rationale |
|---|---|---|
| Buttons | Own plugin, not Meta Bind | Needs are narrow and vault-specific; Meta Bind's expensive half (inline CM6 widgets, two-way frontmatter binding) is unused here |
| Coverage status source | Claude judges; user can pin | Sync sets status automatically, but a row marked `Pinned: yes` is never overwritten |
| Ingest mechanism | Headless `claude -p` via `child_process` | One click, fully automatic. Chosen over a queue file with the unsupervised-write trade-off understood |
| Granularity | Status + script station | Turns the table into a pacing map, not just a checklist |
| Layout | Two-pane (Option B) | Sources and coverage both first-class; coverage grouped by station recovers most of the station-board view |
## Architecture
```
.obsidian/plugins/webinar-dash/
manifest.json
main.js # plain CommonJS, no build step
styles.css # tesanti tokens scoped to .webinar-dash
dashboard.md # vault root, beside index.md
wiki/script-coverage.md # the coverage table
```
`dashboard.md` holds only a config block; the plugin renders everything:
````markdown
# Webinar dashboard
```webinar-dash
script: raw/sources/Webinar script.md
coverage: wiki/script-coverage.md
```
````
Config keys are optional and fall back to those two defaults.
### Where truth lives
| Data | Source of truth | Mechanism |
|---|---|---|
| Which sources are processed | Filesystem, read live | Diff `raw/sources/*.md` against the `**Raw path:**` value in every `wiki/sources/*.md` |
| Concept coverage status | `wiki/script-coverage.md` | Written by Claude on sync, read by the plugin |
Mechanical facts come from the filesystem, judgment comes from the markdown file.
This makes the `index.md` class of drift structurally impossible on the sources half:
the dashboard cannot disagree with the filesystem because it derives from it.
**The plugin never writes to the vault.** It reads files and spawns one subprocess.
Nothing else. It also never reads `index.md` — the catalog is a human-facing artifact,
and treating it as input would reintroduce exactly the drift this design removes.
### Source pipeline derivation
1. List `raw/sources/*.md`.
2. For each `wiki/sources/*.md`, extract the backticked path from the line matching
`**Raw path:** \`<path>\``. Verified consistent across all 9 existing source pages.
3. A raw file claimed by some source page is **processed**; unclaimed is **unprocessed**.
4. A source page whose raw path no longer exists is reported as **orphaned**.
`raw/notes/` is out of scope — those are notes, not sources.
## Coverage file format
```markdown
# Script coverage
#coverage
## Metadata
- **Script:** `raw/sources/Webinar script.md`
- **Last synced:** 2026-07-28
- **Stations:** Chat box · ReAct · Tools · Memory · Skills · Process · OS
## Coverage
| Concept | Status | Station | Pinned |
|---|---|---|---|
| [[harness]] | covered | Tools | |
| [[agentic-loops]] | partial | Process | |
| [[levels-of-ai-usage]] | partial | all | |
| [[connections-as-moat]] | absent | — | yes |
```
Field rules:
- **Concept** — an Obsidian wikilink to a page in `wiki/concepts/`. The plugin extracts
the page name from inside the brackets.
- **Status** — exactly one of `covered`, `partial`, `absent`. Any other value renders as
`invalid` rather than being silently coerced.
- **Station** — one of the seven station names, a comma-separated list of them, `all`,
or `` for none.
- **Pinned** — `yes`, or blank. Blank is the default.
The seven stations are the `#` headings of the script that represent technology levels:
Chat box, ReAct, Tools, Memory, Skills, Process, OS. The script's `Intro`,
`Mail from boss`, and `Notes` headings are setup and are not stations.
v1 does not write this file from the plugin. Pinning is a hand-edit of one cell — a pin
toggle button would make the plugin a writer and risk clobbering concurrent user edits,
which is not worth it for a one-word change.
## Rendering — two-pane layout
Left pane (38%):
- **Queue** — unprocessed sources, each row showing filename, byte size, and an
**Ingest** button. Files missing from `index.md` need no special flag: they appear
here purely because no source page claims them, which is how
`Agentic Engineering, explained by a 10x developer.md` surfaces despite being absent
from the catalog.
- **Ingested** — processed sources as compact rows: date from the source page filename
prefix, plus title.
Right pane (62%):
- Coverage meter — a stacked bar of covered / partial / absent with a 2px gap between
segments, plus a counted key.
- Coverage table grouped by station, with `No station` last.
Collapses to a single column below 820px so a narrow Obsidian pane stays usable.
Styling follows the tesanti design system: black / white / red only, Space Grotesk
display, Inter body, JetBrains Mono for eyebrows and data, radii at most 6px, 1px
hairlines instead of shadows, Lucide stroke icons, no emoji. Status colors use the
system's `--ok` / `--warn` / `--danger` tokens and always ship with a text label, never
color alone. Dark mode is derived from the same ink ramp, with the red lifted to
`#ff4a3d` so small text clears contrast on near-black.
## Ingest mechanism
```js
const { spawn } = require("child_process");
spawn("claude", ["-p", `ingest "${file}"`], { cwd: vaultPath, shell: true });
```
`shell: true` is required on Windows to resolve `claude.cmd`, which places the filename
inside a shell string. Before spawning, the filename is rejected if it contains any of:
`"` `` ` `` `$` `&` `|` `;` `<` `>` `%` or a newline. Existing filenames include
Cyrillic, spaces, and `!`, all of which pass. A rejected filename shows an error in its
row and does not spawn.
Vault path comes from `app.vault.adapter.getBasePath()` on `FileSystemAdapter`.
Per-row states: `idle` → `running` with elapsed seconds → `done` or `failed · exit <n>`
with captured stderr in an expandable block. On success the pipeline is re-derived and
the row moves to the ingested list. A second click while running is ignored.
A global **Sync coverage** button spawns `claude -p "sync script coverage"`.
Preflight: if `claude` is not resolvable on PATH, all buttons render disabled with that
reason stated.
### Accepted risk
Headless ingest writes source summaries, concept pages, `index.md`, and `log.md` without
the user watching. This was chosen deliberately over a review checkpoint. Mitigations:
one file per click rather than a batch, captured output retained per row, and visible
per-row status. The writes land before the user reads them; this is understood and
accepted.
## CLAUDE.md changes
1. **Folder convention** — add `wiki/script-coverage.md` to the tree with a note that it
is machine-maintained.
2. **Tagging rules** — add the row `wiki/script-coverage.md` → `#coverage`. No existing
page type fits: it is generated tabular data, not prose analysis.
3. **Workflow D: Sync Script Coverage** — re-read the script and every
`wiki/concepts/*.md`; set `Status` and `Station` for each; never modify a row whose
`Pinned` is `yes`; add rows for new concept pages; remove rows for deleted ones;
update `Last synced`; then update `index.md` and append to `log.md`.
4. **Sync triggers** — Workflow D runs at the end of any ingest that creates or modifies
a concept page, whenever `Webinar script.md` changes, and on the explicit
`sync script coverage` intent, which is added to Operational Commands.
The coverage baseline is always the raw script at `raw/sources/Webinar script.md`.
Ingesting the script into `wiki/sources/` later does not change the baseline.
## Failure modes
| Condition | Behavior |
|---|---|
| Coverage file missing or table malformed | Sources pane renders normally; coverage pane shows a parse error with the offending line |
| Concept page exists with no table row | Rendered as `unsynced`, so a stale sync is visible rather than silent |
| Table row points at a nonexistent concept page | Rendered as `stale`, kept in place, not auto-removed |
| Source page whose raw path is missing | Listed under `orphaned` in the left pane |
| `child_process` unavailable (mobile) | Buttons render disabled with the reason |
| `claude` not on PATH | Buttons render disabled with the reason |
## Initial coverage assessment
Read manually while designing; the first real sync will regenerate it. 19 concepts:
5 covered, 4 partial, 10 absent.
- **covered** — harness (Tools), skills-as-memory (Skills), solve-first-then-skillify
(Skills), personal-ai-operating-system (OS), evolution-of-agent-tooling (Tools)
- **partial** — agentic-loops (Process), context-as-scarce-resource (Memory),
levels-of-ai-usage (all), code-as-throwaway (OS)
- **absent** — connections-as-moat, product-ownership, seniority-and-the-junior-squeeze,
decoupling-identity-from-profession, network-from-a-standing-start,
think-wider-not-bigger, make-more-cheap-code, enterprise-ai-reality,
integration-dead-ends, leave-less-room-for-imagination
Eight of the ten absent concepts are human-side or strategy-side per `index.md`'s grouping.
The other two — `integration-dead-ends` and `leave-less-room-for-imagination` — are
machine-side, and are absent because the script demonstrates the happy path and so never
reaches connector gating or spec ambiguity, the two ways the machine side fails in
practice. The `ReAct` station carries no wiki concept at all.
## Out of scope for v1
- Pin toggle button (hand-edit instead).
- Alternate station-board view toggle. The data file is layout-independent, so this is a
render change if wanted later.
- Coverage for entities, sources, or queries — concepts only.
- Any view of `raw/notes/`.
## Note on spec location
This file introduces a `docs/` folder at the vault root, which is not part of the
`CLAUDE.md` folder convention and will appear in Obsidian's file explorer. It can be
moved or deleted without affecting the implementation.
The vault is not a git repository, so this spec is not committed.
# Webinar vault dashboard — design
Date: 2026-07-28
Status: approved, ready for implementation planning
## Context
The vault is an LLM-maintained wiki governed by `CLAUDE.md`. It currently holds 12 raw
sources, 9 ingested source summaries, 19 concept pages, and one webinar script
(`raw/sources/Webinar script.md`) that the concepts are supposed to feed.
Two problems motivated this work:
1. **The manual catalog drifts.** `index.md` lists `Ideas for webinar.md` and
`my theses.md` under `raw/sources/`, but both live in `raw/notes/`. It does not
mention `Agentic Engineering, explained by a 10x developer.md` at all, which sits
un-ingested in `raw/sources/`. Nothing detects this.
2. **No view of script coverage.** There is no way to see which concept pages the
webinar script actually delivers. A manual read shows the script is entirely
machine-side: all human-side and strategy-side concepts are absent.
## Goals
- Show processed and unprocessed sources, with a one-click ingest on the unprocessed.
- Show every concept and whether the webinar script mentions it, plus which script
station it lands in.
- Keep coverage status in a separate markdown file, kept synchronized by a rule in
`CLAUDE.md`.
## Non-goals
- Replacing `index.md` or `log.md`. Both stay exactly as they are.
- A general-purpose Obsidian dashboard framework. This is one vault-specific plugin.
- Publishing the plugin to the community plugin registry.
## Decisions taken
| Decision | Choice | Rationale |
|---|---|---|
| Buttons | Own plugin, not Meta Bind | Needs are narrow and vault-specific; Meta Bind's expensive half (inline CM6 widgets, two-way frontmatter binding) is unused here |
| Coverage status source | Claude judges; user can pin | Sync sets status automatically, but a row marked `Pinned: yes` is never overwritten |
| Ingest mechanism | Headless `claude -p` via `child_process` | One click, fully automatic. Chosen over a queue file with the unsupervised-write trade-off understood |
| Granularity | Status + script station | Turns the table into a pacing map, not just a checklist |
| Layout | Two-pane (Option B) | Sources and coverage both first-class; coverage grouped by station recovers most of the station-board view |
## Architecture
```
.obsidian/plugins/webinar-dash/
manifest.json
main.js # plain CommonJS, no build step
styles.css # tesanti tokens scoped to .webinar-dash
dashboard.md # vault root, beside index.md
wiki/script-coverage.md # the coverage table
```
`dashboard.md` holds only a config block; the plugin renders everything:
````markdown
# Webinar dashboard
```webinar-dash
script: raw/sources/Webinar script.md
coverage: wiki/script-coverage.md
```
````
Config keys are optional and fall back to those two defaults.
### Where truth lives
| Data | Source of truth | Mechanism |
|---|---|---|
| Which sources are processed | Filesystem, read live | Diff `raw/sources/*.md` against the `**Raw path:**` value in every `wiki/sources/*.md` |
| Concept coverage status | `wiki/script-coverage.md` | Written by Claude on sync, read by the plugin |
Mechanical facts come from the filesystem, judgment comes from the markdown file.
This makes the `index.md` class of drift structurally impossible on the sources half:
the dashboard cannot disagree with the filesystem because it derives from it.
**The plugin never writes to the vault.** It reads files and spawns one subprocess.
Nothing else. It also never reads `index.md` — the catalog is a human-facing artifact,
and treating it as input would reintroduce exactly the drift this design removes.
### Source pipeline derivation
1. List `raw/sources/*.md`.
2. For each `wiki/sources/*.md`, extract the backticked path from the line matching
`**Raw path:** \`<path>\``. Verified consistent across all 9 existing source pages.
3. A raw file claimed by some source page is **processed**; unclaimed is **unprocessed**.
4. A source page whose raw path no longer exists is reported as **orphaned**.
`raw/notes/` is out of scope — those are notes, not sources.
## Coverage file format
```markdown
# Script coverage
#coverage
## Metadata
- **Script:** `raw/sources/Webinar script.md`
- **Last synced:** 2026-07-28
- **Stations:** Chat box · ReAct · Tools · Memory · Skills · Process · OS
## Coverage
| Concept | Status | Station | Pinned |
|---|---|---|---|
| [[harness]] | covered | Tools | |
| [[agentic-loops]] | partial | Process | |
| [[levels-of-ai-usage]] | partial | all | |
| [[connections-as-moat]] | absent | — | yes |
```
Field rules:
- **Concept** — an Obsidian wikilink to a page in `wiki/concepts/`. The plugin extracts
the page name from inside the brackets.
- **Status** — exactly one of `covered`, `partial`, `absent`. Any other value renders as
`invalid` rather than being silently coerced.
- **Station** — one of the seven station names, a comma-separated list of them, `all`,
or `` for none.
- **Pinned** — `yes`, or blank. Blank is the default.
The seven stations are the `#` headings of the script that represent technology levels:
Chat box, ReAct, Tools, Memory, Skills, Process, OS. The script's `Intro`,
`Mail from boss`, and `Notes` headings are setup and are not stations.
v1 does not write this file from the plugin. Pinning is a hand-edit of one cell — a pin
toggle button would make the plugin a writer and risk clobbering concurrent user edits,
which is not worth it for a one-word change.
## Rendering — two-pane layout
Left pane (38%):
- **Queue** — unprocessed sources, each row showing filename, byte size, and an
**Ingest** button. Files missing from `index.md` need no special flag: they appear
here purely because no source page claims them, which is how
`Agentic Engineering, explained by a 10x developer.md` surfaces despite being absent
from the catalog.
- **Ingested** — processed sources as compact rows: date from the source page filename
prefix, plus title.
Right pane (62%):
- Coverage meter — a stacked bar of covered / partial / absent with a 2px gap between
segments, plus a counted key.
- Coverage table grouped by station, with `No station` last.
Collapses to a single column below 820px so a narrow Obsidian pane stays usable.
Styling follows the tesanti design system: black / white / red only, Space Grotesk
display, Inter body, JetBrains Mono for eyebrows and data, radii at most 6px, 1px
hairlines instead of shadows, Lucide stroke icons, no emoji. Status colors use the
system's `--ok` / `--warn` / `--danger` tokens and always ship with a text label, never
color alone. Dark mode is derived from the same ink ramp, with the red lifted to
`#ff4a3d` so small text clears contrast on near-black.
## Ingest mechanism
```js
const { spawn } = require("child_process");
spawn("claude", ["-p", `ingest "${file}"`], { cwd: vaultPath, shell: true });
```
`shell: true` is required on Windows to resolve `claude.cmd`, which places the filename
inside a shell string. Before spawning, the filename is rejected if it contains any of:
`"` `` ` `` `$` `&` `|` `;` `<` `>` `%` or a newline. Existing filenames include
Cyrillic, spaces, and `!`, all of which pass. A rejected filename shows an error in its
row and does not spawn.
Vault path comes from `app.vault.adapter.getBasePath()` on `FileSystemAdapter`.
Per-row states: `idle` → `running` with elapsed seconds → `done` or `failed · exit <n>`
with captured stderr in an expandable block. On success the pipeline is re-derived and
the row moves to the ingested list. A second click while running is ignored.
A global **Sync coverage** button spawns `claude -p "sync script coverage"`.
Preflight: if `claude` is not resolvable on PATH, all buttons render disabled with that
reason stated.
### Accepted risk
Headless ingest writes source summaries, concept pages, `index.md`, and `log.md` without
the user watching. This was chosen deliberately over a review checkpoint. Mitigations:
one file per click rather than a batch, captured output retained per row, and visible
per-row status. The writes land before the user reads them; this is understood and
accepted.
## CLAUDE.md changes
1. **Folder convention** — add `wiki/script-coverage.md` to the tree with a note that it
is machine-maintained.
2. **Tagging rules** — add the row `wiki/script-coverage.md` → `#coverage`. No existing
page type fits: it is generated tabular data, not prose analysis.
3. **Workflow D: Sync Script Coverage** — re-read the script and every
`wiki/concepts/*.md`; set `Status` and `Station` for each; never modify a row whose
`Pinned` is `yes`; add rows for new concept pages; remove rows for deleted ones;
update `Last synced`; then update `index.md` and append to `log.md`.
4. **Sync triggers** — Workflow D runs at the end of any ingest that creates or modifies
a concept page, whenever `Webinar script.md` changes, and on the explicit
`sync script coverage` intent, which is added to Operational Commands.
The coverage baseline is always the raw script at `raw/sources/Webinar script.md`.
Ingesting the script into `wiki/sources/` later does not change the baseline.
## Failure modes
| Condition | Behavior |
|---|---|
| Coverage file missing or table malformed | Sources pane renders normally; coverage pane shows a parse error with the offending line |
| Concept page exists with no table row | Rendered as `unsynced`, so a stale sync is visible rather than silent |
| Table row points at a nonexistent concept page | Rendered as `stale`, kept in place, not auto-removed |
| Source page whose raw path is missing | Listed under `orphaned` in the left pane |
| `child_process` unavailable (mobile) | Buttons render disabled with the reason |
| `claude` not on PATH | Buttons render disabled with the reason |
## Initial coverage assessment
Read manually while designing; the first real sync will regenerate it. 19 concepts:
5 covered, 4 partial, 10 absent.
- **covered** — harness (Tools), skills-as-memory (Skills), solve-first-then-skillify
(Skills), personal-ai-operating-system (OS), evolution-of-agent-tooling (Tools)
- **partial** — agentic-loops (Process), context-as-scarce-resource (Memory),
levels-of-ai-usage (all), code-as-throwaway (OS)
- **absent** — connections-as-moat, product-ownership, seniority-and-the-junior-squeeze,
decoupling-identity-from-profession, network-from-a-standing-start,
think-wider-not-bigger, make-more-cheap-code, enterprise-ai-reality,
integration-dead-ends, leave-less-room-for-imagination
Eight of the ten absent concepts are human-side or strategy-side per `index.md`'s grouping.
The other two — `integration-dead-ends` and `leave-less-room-for-imagination` — are
machine-side, and are absent because the script demonstrates the happy path and so never
reaches connector gating or spec ambiguity, the two ways the machine side fails in
practice. The `ReAct` station carries no wiki concept at all.
## Out of scope for v1
- Pin toggle button (hand-edit instead).
- Alternate station-board view toggle. The data file is layout-independent, so this is a
render change if wanted later.
- Coverage for entities, sources, or queries — concepts only.
- Any view of `raw/notes/`.
## Note on spec location
This file introduces a `docs/` folder at the vault root, which is not part of the
`CLAUDE.md` folder convention and will appear in Obsidian's file explorer. It can be
moved or deleted without affecting the implementation.
The vault is not a git repository, so this spec is not committed.

178
index.md
View File

@@ -1,89 +1,89 @@
# Wiki Index
Content catalog for this vault. Updated after every ingest / query / lint operation that changes the wiki.
See [[overview]] for the top-level synthesis and navigation.
Every wiki page carries a page-type tag under its H1 (`#source`, `#entity`, `#concept`, `#timeline`, `#comparison`, `#query`, `#lint-report`, `#overview`) — see "Tagging Rules" in `CLAUDE.md`.
## Sources
- [[2026-07-14-everything-we-knew-about-software-has-changed]] — Theo Browne (AIE): model eras, think wider, code as throwaway _(raw: Everything we knew about software has changed.md)_
- [[2026-07-14-gap-between-ai-users-irreversible]] — Allie Miller: personal AI OS, foundation docs, skills, proactive workflows _(raw: In 1 Year, the Gap Between AI Users and Everyone Else Will Be Irreversible.md)_
- [[2026-07-14-sebastian-eugene-interview]] — Sebastian + Eugene: harness, team collapse, connections, enterprise reality _(raw: sebastian interview - conclusions and insights.md)_
- [[2026-07-14-skills-based-on-git]] — Konstantin (Sber): git skills as agent memory, harness, agent loops _(raw: Скиллы на базе git — новая память AI-агентов.md)_
- [[2026-07-14-nina-interview]] — Eugene + Nina (HR): transcript > summary, friction not resistance, skills as handoff _(raw: Nina interview.md)_
- [[2026-07-14-yulia-interview]] — Eugene + Yulia (HR lead): levels of AI usage, candidate knowledge base, solve-first _(raw: Yulia interview.md)_
- [[2026-07-21-larysa-interview]] — Eugene + Larysa (BA/PM): memory loss, integration dead-ends, less room for imagination _(raw: Larysa interview.md)_
- [[2026-07-22-ai-is-stupid]] — YouTube short (author unknown): "stupid AI" = model minus context minus harness; Nobel-vs-employee analogy _(raw: ИИ глупый!.md)_
- [[2026-07-24-youre-reading-way-too-much-code]] — Theo Browne (video): make more cheap code, four tiers of code, 100:1 slop-to-ship verification _(raw: You're reading way too much code.md)_
**Raw, not yet ingested:** `raw/sources/Agentic Engineering, explained by a 10x developer.md` · `raw/sources/Webinar Plan - From Chat Box to Your Own OS.md` · `raw/sources/Webinar script.md`
## Coverage
- [[script-coverage]] — every concept vs `raw/sources/Webinar script.md`; 5 covered, 4 partial, 10 absent
## Entities
### People
- [[theo-browne]] — developer/educator (t3.gg); "think wider", "make more cheap code"
- [[allie-miller]] — ex-Amazon AI leader; personal AI OS
- [[sebastian]] — founder of Virtido; enterprise/connections lens
- [[eugene]] — developer, harness-builder, webinar author; interviewer (likely vault owner, tentative)
- [[konstantin]] — Sber/GigaChat R&D; skills-as-memory
- [[nina]] — HR recruiter at Virtido; webinar-audience proxy, use-case supplier
- [[yulia]] — HR/recruiting lead; webinar organizer (name/affiliation tentative)
- [[larysa]] — technical BA/PM, ex-mobile dev; advanced user blocked by memory + integrations
### Tools / Orgs
- [[claude-code]] — reference harness (all sources)
- [[hermes]] — skills-first, self-curating harness
- [[virtido]] — Sebastian's outsourcing company; its HR team is the webinar audience
- [[inspectron]] — Eugene's employer (Edge Compute / IoT)
## Concepts
**Machine side**
- [[harness]] — universal agent = LLM + small toolset + loop
- [[skills-as-memory]] — git skills (SKILL.md + tools + data) as agent memory
- [[evolution-of-agent-tooling]] — tools → MCP → skills
- [[agentic-loops]] — inner (ReAct) / outer (Ralph) / meta
- [[context-as-scarce-resource]] — the binding constraint; the "smart zone"
- [[personal-ai-operating-system]] — Allie's context docs + skills + proactive workflows
- [[levels-of-ai-usage]] — Eugene's ladder: chatbot → … → CLAUDE.md + skills (the non-programmer ceiling)
- [[solve-first-then-skillify]] — solve the task once, then freeze it into a skill
- [[integration-dead-ends]] — agent starts work against connectors the user's account doesn't have
- [[leave-less-room-for-imagination]] — every gap in a spec gets filled, invisibly; tighten it
**Human side**
- [[product-ownership]] — own outcomes, frame problems not tickets
- [[connections-as-moat]] — in-person relationships as the last non-commoditized asset
- [[network-from-a-standing-start]] — tentative from-zero networking protocol (v0, to be validated)
- [[seniority-and-the-junior-squeeze]] — judgment as risk-reduction
- [[decoupling-identity-from-profession]] — separate who you are from what you do
**Strategy side**
- [[think-wider-not-bigger]] — breadth over depth; match ambition to the model
- [[code-as-throwaway]] — cost of code → zero
- [[make-more-cheap-code]] — Theo: four tiers of code; generate never-shipped slop to verify/explore; there's always another layer
- [[enterprise-ai-reality]] — compliance lock-down; the company-managed-harness market
## Timelines
- [[ai-agent-evolution]] — agent/tooling timeline + Theo's model eras
## Comparisons
- [[theo-konstantin-allie]] — Theo vs Konstantin vs Allie: three lenses (strategy / engineering / personal-OS) on the same shift; shared markdown-as-unit and system-over-model, differing altitude
## Queries
- [[2026-07-14-best-first-skill-for-beginner]] — best first skill for a Claude beginner: skill-creator (meta) + tone-of-voice/anti-AI-language; foundation docs first
- [[2026-07-14-network-from-standing-start]] — network-from-zero: tentative protocol + Sebastian round-2 interview instrument (10 questions)
- [[2026-07-22-webinar-theses]] — 14 candidate theses for the webinar, grouped spine / stakes / obstacles / method / tensions
- [[2026-07-24-non-engineer-throwaway-verification]] — non-engineer analog of throwaway verification code: generated checks not content; checker skills; drift as diagnostic
## Lint Reports
_None yet._
# Wiki Index
Content catalog for this vault. Updated after every ingest / query / lint operation that changes the wiki.
See [[overview]] for the top-level synthesis and navigation.
Every wiki page carries a page-type tag under its H1 (`#source`, `#entity`, `#concept`, `#timeline`, `#comparison`, `#query`, `#lint-report`, `#overview`) — see "Tagging Rules" in `CLAUDE.md`.
## Sources
- [[2026-07-14-everything-we-knew-about-software-has-changed]] — Theo Browne (AIE): model eras, think wider, code as throwaway _(raw: Everything we knew about software has changed.md)_
- [[2026-07-14-gap-between-ai-users-irreversible]] — Allie Miller: personal AI OS, foundation docs, skills, proactive workflows _(raw: In 1 Year, the Gap Between AI Users and Everyone Else Will Be Irreversible.md)_
- [[2026-07-14-sebastian-eugene-interview]] — Sebastian + Eugene: harness, team collapse, connections, enterprise reality _(raw: sebastian interview - conclusions and insights.md)_
- [[2026-07-14-skills-based-on-git]] — Konstantin (Sber): git skills as agent memory, harness, agent loops _(raw: Скиллы на базе git — новая память AI-агентов.md)_
- [[2026-07-14-nina-interview]] — Eugene + Nina (HR): transcript > summary, friction not resistance, skills as handoff _(raw: Nina interview.md)_
- [[2026-07-14-yulia-interview]] — Eugene + Yulia (HR lead): levels of AI usage, candidate knowledge base, solve-first _(raw: Yulia interview.md)_
- [[2026-07-21-larysa-interview]] — Eugene + Larysa (BA/PM): memory loss, integration dead-ends, less room for imagination _(raw: Larysa interview.md)_
- [[2026-07-22-ai-is-stupid]] — YouTube short (author unknown): "stupid AI" = model minus context minus harness; Nobel-vs-employee analogy _(raw: ИИ глупый!.md)_
- [[2026-07-24-youre-reading-way-too-much-code]] — Theo Browne (video): make more cheap code, four tiers of code, 100:1 slop-to-ship verification _(raw: You're reading way too much code.md)_
**Raw, not yet ingested:** `raw/sources/Agentic Engineering, explained by a 10x developer.md` · `raw/sources/Webinar Plan - From Chat Box to Your Own OS.md` · `raw/sources/Webinar script.md`
## Coverage
- [[script-coverage]] — every concept vs `raw/sources/Webinar script.md`; 5 covered, 4 partial, 10 absent
## Entities
### People
- [[theo-browne]] — developer/educator (t3.gg); "think wider", "make more cheap code"
- [[allie-miller]] — ex-Amazon AI leader; personal AI OS
- [[sebastian]] — founder of Virtido; enterprise/connections lens
- [[eugene]] — developer, harness-builder, webinar author; interviewer (likely vault owner, tentative)
- [[konstantin]] — Sber/GigaChat R&D; skills-as-memory
- [[nina]] — HR recruiter at Virtido; webinar-audience proxy, use-case supplier
- [[yulia]] — HR/recruiting lead; webinar organizer (name/affiliation tentative)
- [[larysa]] — technical BA/PM, ex-mobile dev; advanced user blocked by memory + integrations
### Tools / Orgs
- [[claude-code]] — reference harness (all sources)
- [[hermes]] — skills-first, self-curating harness
- [[virtido]] — Sebastian's outsourcing company; its HR team is the webinar audience
- [[inspectron]] — Eugene's employer (Edge Compute / IoT)
## Concepts
**Machine side**
- [[harness]] — universal agent = LLM + small toolset + loop
- [[skills-as-memory]] — git skills (SKILL.md + tools + data) as agent memory
- [[evolution-of-agent-tooling]] — tools → MCP → skills
- [[agentic-loops]] — inner (ReAct) / outer (Ralph) / meta
- [[context-as-scarce-resource]] — the binding constraint; the "smart zone"
- [[personal-ai-operating-system]] — Allie's context docs + skills + proactive workflows
- [[levels-of-ai-usage]] — Eugene's ladder: chatbot → … → CLAUDE.md + skills (the non-programmer ceiling)
- [[solve-first-then-skillify]] — solve the task once, then freeze it into a skill
- [[integration-dead-ends]] — agent starts work against connectors the user's account doesn't have
- [[leave-less-room-for-imagination]] — every gap in a spec gets filled, invisibly; tighten it
**Human side**
- [[product-ownership]] — own outcomes, frame problems not tickets
- [[connections-as-moat]] — in-person relationships as the last non-commoditized asset
- [[network-from-a-standing-start]] — tentative from-zero networking protocol (v0, to be validated)
- [[seniority-and-the-junior-squeeze]] — judgment as risk-reduction
- [[decoupling-identity-from-profession]] — separate who you are from what you do
**Strategy side**
- [[think-wider-not-bigger]] — breadth over depth; match ambition to the model
- [[code-as-throwaway]] — cost of code → zero
- [[make-more-cheap-code]] — Theo: four tiers of code; generate never-shipped slop to verify/explore; there's always another layer
- [[enterprise-ai-reality]] — compliance lock-down; the company-managed-harness market
## Timelines
- [[ai-agent-evolution]] — agent/tooling timeline + Theo's model eras
## Comparisons
- [[theo-konstantin-allie]] — Theo vs Konstantin vs Allie: three lenses (strategy / engineering / personal-OS) on the same shift; shared markdown-as-unit and system-over-model, differing altitude
## Queries
- [[2026-07-14-best-first-skill-for-beginner]] — best first skill for a Claude beginner: skill-creator (meta) + tone-of-voice/anti-AI-language; foundation docs first
- [[2026-07-14-network-from-standing-start]] — network-from-zero: tentative protocol + Sebastian round-2 interview instrument (10 questions)
- [[2026-07-22-webinar-theses]] — 14 candidate theses for the webinar, grouped spine / stakes / obstacles / method / tensions
- [[2026-07-24-non-engineer-throwaway-verification]] — non-engineer analog of throwaway verification code: generated checks not content; checker skills; drift as diagnostic
## Lint Reports
_None yet._

314
log.md
View File

@@ -1,157 +1,157 @@
# Operation Log
Append-only chronological record of wiki operations. Newest entries at the bottom.
Entry format:
```
## YYYY-MM-DD — <operation>
- Intent: ingest | query | lint | maintenance | sync
- Input: <source path / question / scope>
- Pages changed: [[...]], [[...]]
- Notes: <what changed, uncertainty, next steps>
```
---
## 2026-07-14 — maintenance
- Intent: maintenance
- Input: Initialize vault folder structure.
- Pages changed: created `index.md`, `log.md`, `wiki/overview.md`; created `raw/{sources,assets}` and `wiki/{sources,entities,concepts,timelines,comparisons,queries,lint-reports}`.
- Notes: Empty vault scaffolded per the LLM Wiki Schema in `CLAUDE.md`. No sources ingested yet. Ready for first "ingest <source>".
## 2026-07-14 — ingest (batch, 4 sources)
- Intent: ingest
- Input: The 4 talk/interview docs (user-selected scope; "Ideas for webinar" + "HR Contacts" left as raw reference).
- `raw/sources/Everything we knew about software has changed.md`
- `raw/sources/In 1 Year, the Gap Between AI Users and Everyone Else Will Be Irreversible.md`
- `raw/sources/sebastian interview - conclusions and insights.md`
- `raw/sources/Скиллы на базе git — новая память AI-агентов.md`
- Pages created — sources (4): [[2026-07-14-everything-we-knew-about-software-has-changed]], [[2026-07-14-gap-between-ai-users-irreversible]], [[2026-07-14-sebastian-eugene-interview]], [[2026-07-14-skills-based-on-git]].
- Pages created — entities (8): [[theo-browne]], [[allie-miller]], [[sebastian]], [[eugene]], [[konstantin]], [[claude-code]], [[hermes]], [[virtido]].
- Pages created — concepts (13): [[harness]], [[skills-as-memory]], [[evolution-of-agent-tooling]], [[agentic-loops]], [[context-as-scarce-resource]], [[personal-ai-operating-system]], [[product-ownership]], [[connections-as-moat]], [[seniority-and-the-junior-squeeze]], [[decoupling-identity-from-profession]], [[think-wider-not-bigger]], [[code-as-throwaway]], [[enterprise-ai-reality]].
- Pages created — timelines (1): [[ai-agent-evolution]].
- Pages updated: [[overview]] (added the cross-source through-line + agree/diverge), `index.md` (full catalog).
- Notes: Strong cross-source convergence (skills-as-memory: Konstantin ↔ Allie; connections: Sebastian ↔ Allie; code-as-throwaway: Theo ↔ Sebastian). Recorded contradictions (Eugene vs Sebastian on BYO- vs company-managed harness, online vs in-person networking, OSS motivation). Tentative claims flagged: Theo's model-era names, Eugene = vault owner, Hermes/Ralph heuristics, Allie's self-learning-models prediction.
- Next: consider ingesting "Ideas for webinar" (connects corpus → webinar plan) and "HR Contacts" (the HR-search demo); consider a `wiki/comparisons/` page for the BYO-vs-managed-harness debate; run "lint wiki" to check link health.
## 2026-07-14 — maintenance (tagging convention)
- Intent: maintenance
- Input: user request — add per-type hashtags to the wiki schema and existing pages.
- Pages changed: `CLAUDE.md` (new "Tagging Rules" section, rule 9, templates + lint checklist updated); all 26 wiki pages received a page-type tag line under their H1 — [[overview]] `#overview`, 4 source pages `#source`, 8 entity pages `#entity`, 13 concept pages `#concept`, [[ai-agent-evolution]] `#timeline`; `index.md` (noted the convention).
- Notes: Tag mapping is folder-driven (`#source`, `#entity`, `#concept`, `#timeline`, `#comparison`, `#query`, `#lint-report`, `#overview`). Exactly one type tag per page, first on the tag line; topical tags may follow. Lint now checks for missing/mismatched type tags.
## 2026-07-14 -- query
- Intent: query
- Input: "what would be the best claude skill to give to a claude beginner user?"
- Pages changed: created [[2026-07-14-best-first-skill-for-beginner]]; updated [[skills-as-memory]] (Next Questions item answered + linked), `index.md` (Queries section).
- Notes: Answer synthesized from Allie Miller (skill-creator, tone-of-voice/anti-AI-language starter set, foundation-docs-first) and Konstantin (>5-tool-calls auto-creation heuristic). Follow-up: contents of a good tone-of-voice SKILL.md; foundation-doc templates.
## 2026-07-14 — maintenance (authorized raw edit)
- Intent: maintenance
- Input: user explicitly authorized editing `raw/sources/Webinar script.md` this session (exception to rule 1).
- Pages changed: `raw/sources/Webinar script.md` — completed the dangling Tools→Memory bridge line, wrote the full **# Memory** section (amnesia demo → notebook tool → close/reopen payoff → system-prompt reveal → user.md beat → tiny-notebook limitation as the Skills hook), and renamed "Markus" → "Marcus" to match the demo app's seeded mail (`Marcus Hale`).
- Notes: Memory section is grounded in the actual mini-game behavior (Level 04 in `D:\Projects\Names\Webinars\From_chat_to_os`): frozen snapshot per session (hence the mandatory close/reopen), `memory.md` + `user.md` on disk, ~2200-char budget motivating Skills. No wiki pages changed. Next: draft **# Skills** section (open with on-demand loading answering the phone-book limitation).
## 2026-07-14 — maintenance (authorized raw edit, Skills section)
- Intent: maintenance
- Input: user request — draft the **# Skills** section in `raw/sources/Webinar script.md` (edit permission granted this session). Corrected flow per user: presenter dictates the operations step by step first, *then* asks AI to package the procedure as a skill.
- Pages changed: `raw/sources/Webinar script.md` — full Skills section (step-by-step dictation → "I was the recipe" → save-as-skill → SKILL.md on disk → fresh-session one-liner → progressive-disclosure reveal → portability beat → "I'm still the alarm clock" hook into Process).
- Notes: Grounded in the app's Skills level (Level 05): `save_skill`/`load_skill`, real `skills/<name>/SKILL.md`, live menu (names+descriptions only) rebuilt per window. No wiki pages changed. Next: draft **# Process** (Level 06 — spawn_process scheduler answers the alarm-clock limitation).
## 2026-07-14 — maintenance (authorized raw edit, Process section)
- Intent: maintenance
- Input: user request — draft the **# Process** section in `raw/sources/Webinar script.md` (session edit permission).
- Pages changed: `raw/sources/Webinar script.md` — full Process section (goal not task → spawn_process with pid → hands-off heartbeats → Override slider makes the cube move by itself → ps/kill → reveal: the shell authored the worker's prompt (AI managing AI) → closing arc: same model all six levels, only the harness grew; harness is unique to you; "from a chat box to your own Agentic Operating System"). Also two-branch rule fixes earlier this session (Memory convention + Skills dictation).
- Notes: Grounded in Level 06 design (`2026-07-11-process-level-design.md`): single ~5s scheduler, stateless ticks, spawn/list/stop syscalls, live 5…+5 weather offset. The "same model, growing harness" close absorbs the `_ideas:` note at the top of the script. Script now has all sections drafted (Intro → Process).
## 2026-07-14 — maintenance (authorized raw edit, OS section)
- Intent: maintenance
- Input: user request — add an **# OS** section to `raw/sources/Webinar script.md` (session edit permission): typing removed, mouse-only interaction with the agent.
- Pages changed: `raw/sources/Webinar script.md` — Process now ends with a "still a terminal / most people never will type" hook; new OS section (one-button app → rule baked in → 5-second checkbox → appliance → "the agent became a program / the chat box dissolved into the OS"); the "same model, growing harness" closing arc moved from Process into OS, with the new final callback "a button that already knows what the email said."
- Notes: Grounded in the OS app design (`2026-07-12-os-app-design.md`): tile 07, status bar mirrors the agent's closing sentence, shared scheduler slot, Override interplay, rule baked into the prompt. Script ladder now: Chat box → ReAct → Tools → Memory → Skills → Process → OS.
## 2026-07-14 — maintenance (authorized raw edit, OS reframing)
- Intent: maintenance
- Input: user correction — the webinar's core idea is "make tools for yourself," not "become a product."
- Pages changed: `raw/sources/Webinar script.md` — Process→OS hook now ends "…and become a tool? A small one. Made for exactly one person."; OS landing gained the intro callback (weekends burned on internal tools → this one took an evening, asked-for not written) and "It dissolved — into the operating system. Into little tools you make for yourself."; closing arc adds "You don't buy it. You build it — one small tool at a time."
- Notes: The OS section now closes the loop with the Intro's internal-tools passion. No wiki pages changed.
## 2026-07-14 — ingest (batch, 2 sources: Nina + Yulia interviews)
- Intent: ingest
- Input: `raw/sources/Nina interview.md`, `raw/sources/Yulia interview.md` (both are conclusions docs auto-generated by Eugene's record→diarize→transcribe→summarize tool).
- Pages created — sources (2): [[2026-07-14-nina-interview]], [[2026-07-14-yulia-interview]].
- Pages created — entities (3): [[nina]] (HR recruiter, Virtido), [[yulia]] (HR lead; name/affiliation tentative, inferred from filename + Nina reference), [[inspectron]] (Eugene's employer).
- Pages created — concepts (2): [[levels-of-ai-usage]] (chatbot → memory → Claude Code → CLAUDE.md → skills → KB → RAG; non-programmer ceiling = CLAUDE.md + skills), [[solve-first-then-skillify]] (solve once, then freeze into a skill; ~3-message and >5-tool-call heuristics).
- Pages updated: [[eugene]] (identity evidence strengthened — webinar author/presenter, Inspectron, $200 max plan, tool builder; still tentative), [[virtido]] (HR team = webinar audience, pain points, tooling), [[skills-as-memory]] (handoff/de-risking payoff, ~3-message heuristic, method link), [[connections-as-moat]] (Eugene independently converges: "the human's role is just to be human"), [[overview]] (6 sources, demand-side bullet, agree/diverge, navigation, open questions), `index.md`.
- Notes: Strong convergence — Eugene ↔ Sebastian/Allie on human-connection residual despite their networking-tactics disagreement; Eugene's ~3-message heuristic ↔ Konstantin's >5-tool-call heuristic. New cross-interview finding: adoption blocked by friction, not resistance. Tentative flags: Yulia's name/affiliation; Eugene's price-rise prediction; Inspectron employment-vs-contracting. Skills-IP-vs-work-product dispute (Eugene vs Sebastian) recorded, unresolved.
- Next: ingest "Ideas for webinar" / "Webinar Plan" / "Webinar script" to connect corpus → deliverable; interview Larysa/Larisa (PM use cases, twice flagged); consider a comparison page "personal vs employer ownership of skills".
## 2026-07-14 — query (network from a standing start)
- Intent: query
- Input: "how does an individual actually build a network from a standing start?" + "go" on the recommended plan (tentative protocol + Sebastian follow-up instrument).
- Pages created: [[network-from-a-standing-start]] (concept, Status: tentative — 5-step protocol: recurring venues → cadence → lead with humanness → engineer second meetings → track second meetings/let referrals work; contested anti-tactics list; webinar flagged as live case study), [[2026-07-14-network-from-standing-start]] (query — 10-question Sebastian round-2 interview instrument in 3 blocks: bootstrap biography / mechanics / falsification of "Big zero").
- Pages updated: [[connections-as-moat]] (open question → protocol + validation plan), [[overview]] (vault-level open question annotated), `index.md` (Concepts + Queries sections).
- Notes: Corpus cannot answer the question directly — protocol is inferred from Sebastian's principles, Allie's prediction, and Eugene's convergent thesis; every claim marked tentative/contested. Key falsification target: whether Sebastian ever had a true standing start (prior-job network as seed). Deep-research complement (weak ties, mere exposure, from-zero playbooks, scoped to test "Big zero") described but not run.
- Next: run the round-2 Sebastian interview and ingest it; decide on the deep-research run; track webinar → paid-HR-build chain as case-study evidence.
## 2026-07-16 — query → comparison
- Intent: query
- Input: "Compare Theo's, Konstantin's ('Sonstantine') and Allie's approaches — what they have in common, what they have different?"
- Pages created: [[theo-konstantin-allie]] (first `wiki/comparisons/` page — three-lens side-by-side: at-a-glance table, 6 shared points, differences by altitude/framing/code/learning/register, complementary tensions).
- Pages updated: [[theo-browne]], [[konstantin]], [[allie-miller]] (added inbound "Comparison:" links to avoid orphan); `index.md` (Comparisons section — first entry).
- Notes: Synthesized from the 3 source summaries + entity pages + [[skills-as-memory]]. Common ground: bottleneck moved model→human system; markdown/skills as the atomic unit; infrastructure compounds; system-ready to absorb new models; context as scarce resource; shared [[claude-code]]. Differences framed as *altitude* (Theo strategy/psychology · Konstantin engineering · Allie individual-productivity), not direction — corpus disagreements lie elsewhere. Recorded the throwaway-code (Theo) vs persist-in-git (Konstantin) tension as complementary (artifact vs capability). No new contradictions. Saved as a comparison rather than a query page since the request was explicitly a side-by-side.
- Next: reusable starter template (foundation docs / good SKILL.md) still unresolved across all three — webinar-relevant; consider whether Konstantin's meta-loop (wipe-and-restart) tensions with "persist everything".
## 2026-07-16 — maintenance (table fix)
- Intent: maintenance
- Input: user report — the table in [[ai-agent-evolution]] "looks broken".
- Pages changed: [[ai-agent-evolution]] — repaired the "Agent architecture & tooling (Konstantin)" table; escaped the `|` inside aliased wiki links (`[[harness\|harnesses]]`, `[[skills-as-memory\|skills]]`, `[[agentic-loops\|agent loops]]`) so Obsidian no longer reads them as column separators, and removed the two phantom trailing columns the unescaped pipes had forced into the header/separator. Now a clean 3-column table (Period / Milestone / Significance).
- Notes: Content unchanged — formatting-only fix. The Theo Browne table was already valid. No `index.md` change (no catalog/structural change). Root cause: piped `[[page|alias]]` links inside GFM/Obsidian table cells require the pipe escaped as `\|`.
## 2026-07-21 — ingest (Larysa interview)
- Intent: ingest
- Input: "ingest Larysa interview.md" → `raw/sources/Larysa interview.md` (auto-generated interview conclusions doc; Eugene × Larysa, technical BA/PM and ex-mobile dev).
- Pages created: [[2026-07-21-larysa-interview]] (source), [[larysa]] (entity), [[integration-dead-ends]] (concept — agent begins work against connectors gated by account tier / paid seat / missing API; corpus offers no fix, only up-front verification), [[leave-less-room-for-imagination]] (concept — under-specified prompts drift and the collateral damage is *invisible*; skills as the constraint; includes the 4.7-over-4.8 model-choice corollary).
- Pages updated: [[skills-as-memory]] (new "negative case" section — built-in memory as anti-feature, the demand-side reason skills exist; contradiction logged vs Allie), [[harness]] (consolidation-over-tool-hopping section + "before and after" claim marked self-reported), [[code-as-throwaway]] (auth/payments trust carve-out; "safe from 4.6 on"), [[levels-of-ai-usage]] (Larysa as proof the rungs are skippable — technically advanced, architecturally stuck), [[claude-code]] (practitioner-limits section: memory, connectors, 4.6/4.7/4.8, emulator), [[solve-first-then-skillify]], [[personal-ai-operating-system]] (cross-ref to Eugene's convergent OS framing), [[eugene]], [[yulia]] (Larisa open question partially resolved), [[virtido]] (audience extends beyond HR; ClickUp/Figma/Teams/Slack), [[overview]] (6→7 sources, demand-side paragraph, two new divergences, two new vault-level open questions), `index.md`.
- Notes: Closes the "Larysa/Larisa not yet interviewed — PM use cases missing" gap flagged in both HR interviews. Key reframe for the webinar: this source moves the diagnosis from *friction* (Nina/Yulia: people would adopt if it were simple) to *structural walls* for users already past friction — memory, entitlements, drift. Two genuine corpus contradictions recorded rather than smoothed: memory-as-anti-feature (Eugene) vs Allie's untroubled use of persistent context docs, and tight-spec vs [[think-wider-not-bigger]]. Also corrected `index.md`: `HR Contacts.md` was listed as not-yet-ingested but does not exist in `raw/sources/` — removed from the list.
- Next: remaining un-ingested raw are the three webinar-deliverable docs (`Ideas for webinar.md`, `Webinar Plan - From Chat Box to Your Own OS.md`, `Webinar script.md`) — ingesting them would connect the corpus to the actual deliverable and settle whether the script keeps the [[levels-of-ai-usage]] rung order. Candidate query: does the skills rung actually answer Larysa's memory complaint, or is hers a cross-project problem skills don't solve? A first lint pass is also overdue (no lint reports exist; 7 sources, 17 concepts).
## 2026-07-22 — query (webinar theses)
- Intent: query
- Input: "What theses can I suggest for the webinar ('from chatbox to your own agentic operating system') based on what you already have?"
- Pages changed: created [[2026-07-22-webinar-theses]]; updated `index.md` (Queries section).
- Notes: 14 candidate theses synthesized from [[overview]], the 7 source summaries, and direct reads of the three raw webinar-deliverable docs (Plan, script, Ideas — still raw-only, cited as raw per policy). Grouped: spine (harness-not-model, app-you-open→OS, skills-as-memory, context scarcity, build-not-buy) / stakes (cost→zero, irreversible gap, connections rise) / obstacles (friction-not-resistance, structural walls, less-room-for-imagination) / method (solve-first-then-skillify, research-vs-judgment, walk-in-a-week) / honest tensions (3 recorded contradictions offered as Q&A ammo). Recommended 7-thesis subset for the 30-min format noted in the query page. No concept/entity pages changed.
- Next: ingest the three deliverable docs so theses can cite wiki sources instead of raw; decide whether the "obstacles" theses earn a station on the spine.
## 2026-07-22 — ingest (ИИ глупый! short)
- Intent: ingest
- Input: "ingest \"ИИ глупый!\"" → `raw/sources/ИИ глупый!.md` (conclusions doc for a 1:28 Russian YouTube Short, author unknown; file was added mid-session after the first lookup found nothing).
- Pages created: [[2026-07-22-ai-is-stupid]] (source).
- Pages updated: [[harness]] (business-facing "engineering wrapper" definition + model+context+harness formula, flagged as webinar language), [[context-as-scarce-resource]] (supply-side facet: "intelligence without context loses to context without intelligence", Nobel-vs-employee analogy; RAG-vs-skills tension logged under Contradictions), [[overview]] (7→8 sources, convergence one-liner, navigation), `index.md` (Sources entry; `my theses.md` added to the not-yet-ingested list).
- Notes: No new concepts — the short *restates* the vault's machine-side spine for a business audience, which makes it webinar-quotable rather than novel. One tension recorded, not smoothed: it recommends RAG/long-term memory as context mechanisms where Konstantin argues skills beat RAG (possibly audience-driven — business data vs procedures). Authorship unknown and marked tentative; its framing matches the corpus closely enough that a connection to someone already in the corpus is worth checking. All ×10…×1000 gain claims are rhetorical, not measured.
- Next: `my theses.md` is new in raw and un-ingested (six webinar thesis one-liners) — small, high-relevance ingest candidate; the three webinar-deliverable docs remain pending; first lint pass still overdue (8 sources, 17 concepts, 0 lint reports).
## 2026-07-24 — ingest (You're reading way too much code)
- Intent: ingest
- Input: "ingest \"You're reading way too much code\"" → `raw/sources/You're reading way too much code.md` (conclusions doc for Theo Browne's 24:11 video; his second source in the vault).
- Pages created: [[2026-07-24-youre-reading-way-too-much-code]] (source), [[make-more-cheap-code]] (concept — ship/no-ship line, four tiers of code AD, 10010,000:1 slop-to-ship verification ratio, always-another-layer, dumb-model agents as API usability testers, reading-costs-attention economics).
- Pages updated: [[code-as-throwaway]] (discipline section; evidence; its "what is the durable artifact" open question partially answered — the verification harness is now a named first-class output), [[theo-browne]] (second talk, recurring author-move noted, self-reported ratios flagged tentative), [[leave-less-room-for-imagination]] (new logged tension: Theo/Dax agent-diff-summaries vs Eugene's invisible-drift claim), [[2026-07-14-everything-we-knew-about-software-has-changed]] (reciprocal related-source link), [[overview]] (8→9 sources; verifying-half of spine given its method; new divergence line; 17→18 concepts), `index.md` (Sources, People, Concepts entries).
- Notes: The source is a *defense with discipline*, not a reversal — Theo explicitly rejects shipping unreviewed slop, which pre-empts the obvious objection to [[code-as-throwaway]]. Strong webinar relevance: "attention, not generation, is the bottleneck" is the engineer-side twin of [[context-as-scarce-resource]], and the tier framework gives audiences a non-binary answer to "can I trust AI code?". One genuine tension recorded rather than smoothed (summaries-hide-drift). Shao's 80%-into-harnesses ratio and all of Theo's daily-line counts are self-reported/uncited — marked tentative. Open framework gap flagged: skills/CLAUDE.md files don't fit the AD spectrum.
- Next: candidate query — what is the non-engineer's analog of throwaway verification code (HR/BA audience)? `my theses.md` and the three webinar-deliverable docs remain un-ingested; first lint pass still overdue (9 sources, 18 concepts, 0 lint reports).
## 2026-07-24 — query (non-engineer throwaway verification)
- Intent: query
- Input: "query: what is the non-engineer's analog of throwaway verification code?" (the candidate query flagged in the previous ingest).
- Pages created: [[2026-07-24-non-engineer-throwaway-verification]] (query — answer: disposable AI work that attacks/misreads/simulates the deliverable before a human sees it; one-to-one mapping table from Theo's engineer patterns to HR/BA use cases; "checker skills" as the second species of skill; tier-D-stays-human caveat since non-engineer verification bottoms out in judgment, not tests).
- Pages updated: [[make-more-cheap-code]] (next-question marked answered, link added), [[leave-less-room-for-imagination]] (new next-question: drift harnessed as a sandboxed ambiguity diagnostic — synthesis, tentative), `index.md` (Queries section).
- Notes: Pure synthesis, no new source — every mapped pattern is grounded in corpus use cases (Nina/Yulia job descriptions, candidate KB, sourcing; Larysa spec ambiguity; Allie's anti-AI-language checker-skill precedent). Key reframes with durable value: (1) the fresh-agent misread test inverts [[leave-less-room-for-imagination]] — drift becomes a diagnostic when sandboxed; (2) [[solve-first-then-skillify]] populates skills in two species, producers and checkers. Flagged honestly: the whole mapping is argument-by-analogy with no measured claim; Nina's transcript-beats-summary finding is a standing counterweight to summary-based review.
- Next: decide whether "checker skills" earns a slide on the webinar's skills rung; the webinar-deliverable docs (`Ideas`, `Plan`, `script`, `my theses.md`) remain un-ingested; first lint pass still overdue (9 sources, 18 concepts, 2026-07-24 now has 1 query, 0 lint reports).
## 2026-07-28 — sync (script coverage, initial)
- Intent: sync script coverage
- Input: first run of Workflow D, establishing `wiki/script-coverage.md`.
- Pages created: [[script-coverage]] (coverage) — 19 rows, one per concept page.
- Pages updated: `CLAUDE.md` (folder convention, `#coverage` tag row, Workflow D, new intent), `index.md` (new Coverage section; corrected the not-yet-ingested list — `Ideas for webinar.md` and `my theses.md` were listed under `raw/sources/` but live in `raw/notes/`, and `Agentic Engineering, explained by a 10x developer.md` was missing entirely).
- Notes: Initial assessment is 5 covered, 4 partial, 10 absent. Eight of the ten absent are human-side or strategy-side per the grouping in index.md; the other two — [[integration-dead-ends]] and [[leave-less-room-for-imagination]] — are machine-side, absent because the script demos the happy path and never reaches connector gating or spec ambiguity. The `ReAct` station carries no wiki concept. No concept pages were edited.
- Next: decide whether the human-side cluster earns a station or is a deliberate cut; decide separately whether the two absent machine-side failure modes belong in the demo; pin the rows that are decided so future syncs leave them alone.
# Operation Log
Append-only chronological record of wiki operations. Newest entries at the bottom.
Entry format:
```
## YYYY-MM-DD — <operation>
- Intent: ingest | query | lint | maintenance | sync
- Input: <source path / question / scope>
- Pages changed: [[...]], [[...]]
- Notes: <what changed, uncertainty, next steps>
```
---
## 2026-07-14 — maintenance
- Intent: maintenance
- Input: Initialize vault folder structure.
- Pages changed: created `index.md`, `log.md`, `wiki/overview.md`; created `raw/{sources,assets}` and `wiki/{sources,entities,concepts,timelines,comparisons,queries,lint-reports}`.
- Notes: Empty vault scaffolded per the LLM Wiki Schema in `CLAUDE.md`. No sources ingested yet. Ready for first "ingest <source>".
## 2026-07-14 — ingest (batch, 4 sources)
- Intent: ingest
- Input: The 4 talk/interview docs (user-selected scope; "Ideas for webinar" + "HR Contacts" left as raw reference).
- `raw/sources/Everything we knew about software has changed.md`
- `raw/sources/In 1 Year, the Gap Between AI Users and Everyone Else Will Be Irreversible.md`
- `raw/sources/sebastian interview - conclusions and insights.md`
- `raw/sources/Скиллы на базе git — новая память AI-агентов.md`
- Pages created — sources (4): [[2026-07-14-everything-we-knew-about-software-has-changed]], [[2026-07-14-gap-between-ai-users-irreversible]], [[2026-07-14-sebastian-eugene-interview]], [[2026-07-14-skills-based-on-git]].
- Pages created — entities (8): [[theo-browne]], [[allie-miller]], [[sebastian]], [[eugene]], [[konstantin]], [[claude-code]], [[hermes]], [[virtido]].
- Pages created — concepts (13): [[harness]], [[skills-as-memory]], [[evolution-of-agent-tooling]], [[agentic-loops]], [[context-as-scarce-resource]], [[personal-ai-operating-system]], [[product-ownership]], [[connections-as-moat]], [[seniority-and-the-junior-squeeze]], [[decoupling-identity-from-profession]], [[think-wider-not-bigger]], [[code-as-throwaway]], [[enterprise-ai-reality]].
- Pages created — timelines (1): [[ai-agent-evolution]].
- Pages updated: [[overview]] (added the cross-source through-line + agree/diverge), `index.md` (full catalog).
- Notes: Strong cross-source convergence (skills-as-memory: Konstantin ↔ Allie; connections: Sebastian ↔ Allie; code-as-throwaway: Theo ↔ Sebastian). Recorded contradictions (Eugene vs Sebastian on BYO- vs company-managed harness, online vs in-person networking, OSS motivation). Tentative claims flagged: Theo's model-era names, Eugene = vault owner, Hermes/Ralph heuristics, Allie's self-learning-models prediction.
- Next: consider ingesting "Ideas for webinar" (connects corpus → webinar plan) and "HR Contacts" (the HR-search demo); consider a `wiki/comparisons/` page for the BYO-vs-managed-harness debate; run "lint wiki" to check link health.
## 2026-07-14 — maintenance (tagging convention)
- Intent: maintenance
- Input: user request — add per-type hashtags to the wiki schema and existing pages.
- Pages changed: `CLAUDE.md` (new "Tagging Rules" section, rule 9, templates + lint checklist updated); all 26 wiki pages received a page-type tag line under their H1 — [[overview]] `#overview`, 4 source pages `#source`, 8 entity pages `#entity`, 13 concept pages `#concept`, [[ai-agent-evolution]] `#timeline`; `index.md` (noted the convention).
- Notes: Tag mapping is folder-driven (`#source`, `#entity`, `#concept`, `#timeline`, `#comparison`, `#query`, `#lint-report`, `#overview`). Exactly one type tag per page, first on the tag line; topical tags may follow. Lint now checks for missing/mismatched type tags.
## 2026-07-14 -- query
- Intent: query
- Input: "what would be the best claude skill to give to a claude beginner user?"
- Pages changed: created [[2026-07-14-best-first-skill-for-beginner]]; updated [[skills-as-memory]] (Next Questions item answered + linked), `index.md` (Queries section).
- Notes: Answer synthesized from Allie Miller (skill-creator, tone-of-voice/anti-AI-language starter set, foundation-docs-first) and Konstantin (>5-tool-calls auto-creation heuristic). Follow-up: contents of a good tone-of-voice SKILL.md; foundation-doc templates.
## 2026-07-14 — maintenance (authorized raw edit)
- Intent: maintenance
- Input: user explicitly authorized editing `raw/sources/Webinar script.md` this session (exception to rule 1).
- Pages changed: `raw/sources/Webinar script.md` — completed the dangling Tools→Memory bridge line, wrote the full **# Memory** section (amnesia demo → notebook tool → close/reopen payoff → system-prompt reveal → user.md beat → tiny-notebook limitation as the Skills hook), and renamed "Markus" → "Marcus" to match the demo app's seeded mail (`Marcus Hale`).
- Notes: Memory section is grounded in the actual mini-game behavior (Level 04 in `D:\Projects\Names\Webinars\From_chat_to_os`): frozen snapshot per session (hence the mandatory close/reopen), `memory.md` + `user.md` on disk, ~2200-char budget motivating Skills. No wiki pages changed. Next: draft **# Skills** section (open with on-demand loading answering the phone-book limitation).
## 2026-07-14 — maintenance (authorized raw edit, Skills section)
- Intent: maintenance
- Input: user request — draft the **# Skills** section in `raw/sources/Webinar script.md` (edit permission granted this session). Corrected flow per user: presenter dictates the operations step by step first, *then* asks AI to package the procedure as a skill.
- Pages changed: `raw/sources/Webinar script.md` — full Skills section (step-by-step dictation → "I was the recipe" → save-as-skill → SKILL.md on disk → fresh-session one-liner → progressive-disclosure reveal → portability beat → "I'm still the alarm clock" hook into Process).
- Notes: Grounded in the app's Skills level (Level 05): `save_skill`/`load_skill`, real `skills/<name>/SKILL.md`, live menu (names+descriptions only) rebuilt per window. No wiki pages changed. Next: draft **# Process** (Level 06 — spawn_process scheduler answers the alarm-clock limitation).
## 2026-07-14 — maintenance (authorized raw edit, Process section)
- Intent: maintenance
- Input: user request — draft the **# Process** section in `raw/sources/Webinar script.md` (session edit permission).
- Pages changed: `raw/sources/Webinar script.md` — full Process section (goal not task → spawn_process with pid → hands-off heartbeats → Override slider makes the cube move by itself → ps/kill → reveal: the shell authored the worker's prompt (AI managing AI) → closing arc: same model all six levels, only the harness grew; harness is unique to you; "from a chat box to your own Agentic Operating System"). Also two-branch rule fixes earlier this session (Memory convention + Skills dictation).
- Notes: Grounded in Level 06 design (`2026-07-11-process-level-design.md`): single ~5s scheduler, stateless ticks, spawn/list/stop syscalls, live 5…+5 weather offset. The "same model, growing harness" close absorbs the `_ideas:` note at the top of the script. Script now has all sections drafted (Intro → Process).
## 2026-07-14 — maintenance (authorized raw edit, OS section)
- Intent: maintenance
- Input: user request — add an **# OS** section to `raw/sources/Webinar script.md` (session edit permission): typing removed, mouse-only interaction with the agent.
- Pages changed: `raw/sources/Webinar script.md` — Process now ends with a "still a terminal / most people never will type" hook; new OS section (one-button app → rule baked in → 5-second checkbox → appliance → "the agent became a program / the chat box dissolved into the OS"); the "same model, growing harness" closing arc moved from Process into OS, with the new final callback "a button that already knows what the email said."
- Notes: Grounded in the OS app design (`2026-07-12-os-app-design.md`): tile 07, status bar mirrors the agent's closing sentence, shared scheduler slot, Override interplay, rule baked into the prompt. Script ladder now: Chat box → ReAct → Tools → Memory → Skills → Process → OS.
## 2026-07-14 — maintenance (authorized raw edit, OS reframing)
- Intent: maintenance
- Input: user correction — the webinar's core idea is "make tools for yourself," not "become a product."
- Pages changed: `raw/sources/Webinar script.md` — Process→OS hook now ends "…and become a tool? A small one. Made for exactly one person."; OS landing gained the intro callback (weekends burned on internal tools → this one took an evening, asked-for not written) and "It dissolved — into the operating system. Into little tools you make for yourself."; closing arc adds "You don't buy it. You build it — one small tool at a time."
- Notes: The OS section now closes the loop with the Intro's internal-tools passion. No wiki pages changed.
## 2026-07-14 — ingest (batch, 2 sources: Nina + Yulia interviews)
- Intent: ingest
- Input: `raw/sources/Nina interview.md`, `raw/sources/Yulia interview.md` (both are conclusions docs auto-generated by Eugene's record→diarize→transcribe→summarize tool).
- Pages created — sources (2): [[2026-07-14-nina-interview]], [[2026-07-14-yulia-interview]].
- Pages created — entities (3): [[nina]] (HR recruiter, Virtido), [[yulia]] (HR lead; name/affiliation tentative, inferred from filename + Nina reference), [[inspectron]] (Eugene's employer).
- Pages created — concepts (2): [[levels-of-ai-usage]] (chatbot → memory → Claude Code → CLAUDE.md → skills → KB → RAG; non-programmer ceiling = CLAUDE.md + skills), [[solve-first-then-skillify]] (solve once, then freeze into a skill; ~3-message and >5-tool-call heuristics).
- Pages updated: [[eugene]] (identity evidence strengthened — webinar author/presenter, Inspectron, $200 max plan, tool builder; still tentative), [[virtido]] (HR team = webinar audience, pain points, tooling), [[skills-as-memory]] (handoff/de-risking payoff, ~3-message heuristic, method link), [[connections-as-moat]] (Eugene independently converges: "the human's role is just to be human"), [[overview]] (6 sources, demand-side bullet, agree/diverge, navigation, open questions), `index.md`.
- Notes: Strong convergence — Eugene ↔ Sebastian/Allie on human-connection residual despite their networking-tactics disagreement; Eugene's ~3-message heuristic ↔ Konstantin's >5-tool-call heuristic. New cross-interview finding: adoption blocked by friction, not resistance. Tentative flags: Yulia's name/affiliation; Eugene's price-rise prediction; Inspectron employment-vs-contracting. Skills-IP-vs-work-product dispute (Eugene vs Sebastian) recorded, unresolved.
- Next: ingest "Ideas for webinar" / "Webinar Plan" / "Webinar script" to connect corpus → deliverable; interview Larysa/Larisa (PM use cases, twice flagged); consider a comparison page "personal vs employer ownership of skills".
## 2026-07-14 — query (network from a standing start)
- Intent: query
- Input: "how does an individual actually build a network from a standing start?" + "go" on the recommended plan (tentative protocol + Sebastian follow-up instrument).
- Pages created: [[network-from-a-standing-start]] (concept, Status: tentative — 5-step protocol: recurring venues → cadence → lead with humanness → engineer second meetings → track second meetings/let referrals work; contested anti-tactics list; webinar flagged as live case study), [[2026-07-14-network-from-standing-start]] (query — 10-question Sebastian round-2 interview instrument in 3 blocks: bootstrap biography / mechanics / falsification of "Big zero").
- Pages updated: [[connections-as-moat]] (open question → protocol + validation plan), [[overview]] (vault-level open question annotated), `index.md` (Concepts + Queries sections).
- Notes: Corpus cannot answer the question directly — protocol is inferred from Sebastian's principles, Allie's prediction, and Eugene's convergent thesis; every claim marked tentative/contested. Key falsification target: whether Sebastian ever had a true standing start (prior-job network as seed). Deep-research complement (weak ties, mere exposure, from-zero playbooks, scoped to test "Big zero") described but not run.
- Next: run the round-2 Sebastian interview and ingest it; decide on the deep-research run; track webinar → paid-HR-build chain as case-study evidence.
## 2026-07-16 — query → comparison
- Intent: query
- Input: "Compare Theo's, Konstantin's ('Sonstantine') and Allie's approaches — what they have in common, what they have different?"
- Pages created: [[theo-konstantin-allie]] (first `wiki/comparisons/` page — three-lens side-by-side: at-a-glance table, 6 shared points, differences by altitude/framing/code/learning/register, complementary tensions).
- Pages updated: [[theo-browne]], [[konstantin]], [[allie-miller]] (added inbound "Comparison:" links to avoid orphan); `index.md` (Comparisons section — first entry).
- Notes: Synthesized from the 3 source summaries + entity pages + [[skills-as-memory]]. Common ground: bottleneck moved model→human system; markdown/skills as the atomic unit; infrastructure compounds; system-ready to absorb new models; context as scarce resource; shared [[claude-code]]. Differences framed as *altitude* (Theo strategy/psychology · Konstantin engineering · Allie individual-productivity), not direction — corpus disagreements lie elsewhere. Recorded the throwaway-code (Theo) vs persist-in-git (Konstantin) tension as complementary (artifact vs capability). No new contradictions. Saved as a comparison rather than a query page since the request was explicitly a side-by-side.
- Next: reusable starter template (foundation docs / good SKILL.md) still unresolved across all three — webinar-relevant; consider whether Konstantin's meta-loop (wipe-and-restart) tensions with "persist everything".
## 2026-07-16 — maintenance (table fix)
- Intent: maintenance
- Input: user report — the table in [[ai-agent-evolution]] "looks broken".
- Pages changed: [[ai-agent-evolution]] — repaired the "Agent architecture & tooling (Konstantin)" table; escaped the `|` inside aliased wiki links (`[[harness\|harnesses]]`, `[[skills-as-memory\|skills]]`, `[[agentic-loops\|agent loops]]`) so Obsidian no longer reads them as column separators, and removed the two phantom trailing columns the unescaped pipes had forced into the header/separator. Now a clean 3-column table (Period / Milestone / Significance).
- Notes: Content unchanged — formatting-only fix. The Theo Browne table was already valid. No `index.md` change (no catalog/structural change). Root cause: piped `[[page|alias]]` links inside GFM/Obsidian table cells require the pipe escaped as `\|`.
## 2026-07-21 — ingest (Larysa interview)
- Intent: ingest
- Input: "ingest Larysa interview.md" → `raw/sources/Larysa interview.md` (auto-generated interview conclusions doc; Eugene × Larysa, technical BA/PM and ex-mobile dev).
- Pages created: [[2026-07-21-larysa-interview]] (source), [[larysa]] (entity), [[integration-dead-ends]] (concept — agent begins work against connectors gated by account tier / paid seat / missing API; corpus offers no fix, only up-front verification), [[leave-less-room-for-imagination]] (concept — under-specified prompts drift and the collateral damage is *invisible*; skills as the constraint; includes the 4.7-over-4.8 model-choice corollary).
- Pages updated: [[skills-as-memory]] (new "negative case" section — built-in memory as anti-feature, the demand-side reason skills exist; contradiction logged vs Allie), [[harness]] (consolidation-over-tool-hopping section + "before and after" claim marked self-reported), [[code-as-throwaway]] (auth/payments trust carve-out; "safe from 4.6 on"), [[levels-of-ai-usage]] (Larysa as proof the rungs are skippable — technically advanced, architecturally stuck), [[claude-code]] (practitioner-limits section: memory, connectors, 4.6/4.7/4.8, emulator), [[solve-first-then-skillify]], [[personal-ai-operating-system]] (cross-ref to Eugene's convergent OS framing), [[eugene]], [[yulia]] (Larisa open question partially resolved), [[virtido]] (audience extends beyond HR; ClickUp/Figma/Teams/Slack), [[overview]] (6→7 sources, demand-side paragraph, two new divergences, two new vault-level open questions), `index.md`.
- Notes: Closes the "Larysa/Larisa not yet interviewed — PM use cases missing" gap flagged in both HR interviews. Key reframe for the webinar: this source moves the diagnosis from *friction* (Nina/Yulia: people would adopt if it were simple) to *structural walls* for users already past friction — memory, entitlements, drift. Two genuine corpus contradictions recorded rather than smoothed: memory-as-anti-feature (Eugene) vs Allie's untroubled use of persistent context docs, and tight-spec vs [[think-wider-not-bigger]]. Also corrected `index.md`: `HR Contacts.md` was listed as not-yet-ingested but does not exist in `raw/sources/` — removed from the list.
- Next: remaining un-ingested raw are the three webinar-deliverable docs (`Ideas for webinar.md`, `Webinar Plan - From Chat Box to Your Own OS.md`, `Webinar script.md`) — ingesting them would connect the corpus to the actual deliverable and settle whether the script keeps the [[levels-of-ai-usage]] rung order. Candidate query: does the skills rung actually answer Larysa's memory complaint, or is hers a cross-project problem skills don't solve? A first lint pass is also overdue (no lint reports exist; 7 sources, 17 concepts).
## 2026-07-22 — query (webinar theses)
- Intent: query
- Input: "What theses can I suggest for the webinar ('from chatbox to your own agentic operating system') based on what you already have?"
- Pages changed: created [[2026-07-22-webinar-theses]]; updated `index.md` (Queries section).
- Notes: 14 candidate theses synthesized from [[overview]], the 7 source summaries, and direct reads of the three raw webinar-deliverable docs (Plan, script, Ideas — still raw-only, cited as raw per policy). Grouped: spine (harness-not-model, app-you-open→OS, skills-as-memory, context scarcity, build-not-buy) / stakes (cost→zero, irreversible gap, connections rise) / obstacles (friction-not-resistance, structural walls, less-room-for-imagination) / method (solve-first-then-skillify, research-vs-judgment, walk-in-a-week) / honest tensions (3 recorded contradictions offered as Q&A ammo). Recommended 7-thesis subset for the 30-min format noted in the query page. No concept/entity pages changed.
- Next: ingest the three deliverable docs so theses can cite wiki sources instead of raw; decide whether the "obstacles" theses earn a station on the spine.
## 2026-07-22 — ingest (ИИ глупый! short)
- Intent: ingest
- Input: "ingest \"ИИ глупый!\"" → `raw/sources/ИИ глупый!.md` (conclusions doc for a 1:28 Russian YouTube Short, author unknown; file was added mid-session after the first lookup found nothing).
- Pages created: [[2026-07-22-ai-is-stupid]] (source).
- Pages updated: [[harness]] (business-facing "engineering wrapper" definition + model+context+harness formula, flagged as webinar language), [[context-as-scarce-resource]] (supply-side facet: "intelligence without context loses to context without intelligence", Nobel-vs-employee analogy; RAG-vs-skills tension logged under Contradictions), [[overview]] (7→8 sources, convergence one-liner, navigation), `index.md` (Sources entry; `my theses.md` added to the not-yet-ingested list).
- Notes: No new concepts — the short *restates* the vault's machine-side spine for a business audience, which makes it webinar-quotable rather than novel. One tension recorded, not smoothed: it recommends RAG/long-term memory as context mechanisms where Konstantin argues skills beat RAG (possibly audience-driven — business data vs procedures). Authorship unknown and marked tentative; its framing matches the corpus closely enough that a connection to someone already in the corpus is worth checking. All ×10…×1000 gain claims are rhetorical, not measured.
- Next: `my theses.md` is new in raw and un-ingested (six webinar thesis one-liners) — small, high-relevance ingest candidate; the three webinar-deliverable docs remain pending; first lint pass still overdue (8 sources, 17 concepts, 0 lint reports).
## 2026-07-24 — ingest (You're reading way too much code)
- Intent: ingest
- Input: "ingest \"You're reading way too much code\"" → `raw/sources/You're reading way too much code.md` (conclusions doc for Theo Browne's 24:11 video; his second source in the vault).
- Pages created: [[2026-07-24-youre-reading-way-too-much-code]] (source), [[make-more-cheap-code]] (concept — ship/no-ship line, four tiers of code AD, 10010,000:1 slop-to-ship verification ratio, always-another-layer, dumb-model agents as API usability testers, reading-costs-attention economics).
- Pages updated: [[code-as-throwaway]] (discipline section; evidence; its "what is the durable artifact" open question partially answered — the verification harness is now a named first-class output), [[theo-browne]] (second talk, recurring author-move noted, self-reported ratios flagged tentative), [[leave-less-room-for-imagination]] (new logged tension: Theo/Dax agent-diff-summaries vs Eugene's invisible-drift claim), [[2026-07-14-everything-we-knew-about-software-has-changed]] (reciprocal related-source link), [[overview]] (8→9 sources; verifying-half of spine given its method; new divergence line; 17→18 concepts), `index.md` (Sources, People, Concepts entries).
- Notes: The source is a *defense with discipline*, not a reversal — Theo explicitly rejects shipping unreviewed slop, which pre-empts the obvious objection to [[code-as-throwaway]]. Strong webinar relevance: "attention, not generation, is the bottleneck" is the engineer-side twin of [[context-as-scarce-resource]], and the tier framework gives audiences a non-binary answer to "can I trust AI code?". One genuine tension recorded rather than smoothed (summaries-hide-drift). Shao's 80%-into-harnesses ratio and all of Theo's daily-line counts are self-reported/uncited — marked tentative. Open framework gap flagged: skills/CLAUDE.md files don't fit the AD spectrum.
- Next: candidate query — what is the non-engineer's analog of throwaway verification code (HR/BA audience)? `my theses.md` and the three webinar-deliverable docs remain un-ingested; first lint pass still overdue (9 sources, 18 concepts, 0 lint reports).
## 2026-07-24 — query (non-engineer throwaway verification)
- Intent: query
- Input: "query: what is the non-engineer's analog of throwaway verification code?" (the candidate query flagged in the previous ingest).
- Pages created: [[2026-07-24-non-engineer-throwaway-verification]] (query — answer: disposable AI work that attacks/misreads/simulates the deliverable before a human sees it; one-to-one mapping table from Theo's engineer patterns to HR/BA use cases; "checker skills" as the second species of skill; tier-D-stays-human caveat since non-engineer verification bottoms out in judgment, not tests).
- Pages updated: [[make-more-cheap-code]] (next-question marked answered, link added), [[leave-less-room-for-imagination]] (new next-question: drift harnessed as a sandboxed ambiguity diagnostic — synthesis, tentative), `index.md` (Queries section).
- Notes: Pure synthesis, no new source — every mapped pattern is grounded in corpus use cases (Nina/Yulia job descriptions, candidate KB, sourcing; Larysa spec ambiguity; Allie's anti-AI-language checker-skill precedent). Key reframes with durable value: (1) the fresh-agent misread test inverts [[leave-less-room-for-imagination]] — drift becomes a diagnostic when sandboxed; (2) [[solve-first-then-skillify]] populates skills in two species, producers and checkers. Flagged honestly: the whole mapping is argument-by-analogy with no measured claim; Nina's transcript-beats-summary finding is a standing counterweight to summary-based review.
- Next: decide whether "checker skills" earns a slide on the webinar's skills rung; the webinar-deliverable docs (`Ideas`, `Plan`, `script`, `my theses.md`) remain un-ingested; first lint pass still overdue (9 sources, 18 concepts, 2026-07-24 now has 1 query, 0 lint reports).
## 2026-07-28 — sync (script coverage, initial)
- Intent: sync script coverage
- Input: first run of Workflow D, establishing `wiki/script-coverage.md`.
- Pages created: [[script-coverage]] (coverage) — 19 rows, one per concept page.
- Pages updated: `CLAUDE.md` (folder convention, `#coverage` tag row, Workflow D, new intent), `index.md` (new Coverage section; corrected the not-yet-ingested list — `Ideas for webinar.md` and `my theses.md` were listed under `raw/sources/` but live in `raw/notes/`, and `Agentic Engineering, explained by a 10x developer.md` was missing entirely).
- Notes: Initial assessment is 5 covered, 4 partial, 10 absent. Eight of the ten absent are human-side or strategy-side per the grouping in index.md; the other two — [[integration-dead-ends]] and [[leave-less-room-for-imagination]] — are machine-side, absent because the script demos the happy path and never reaches connector gating or spec ambiguity. The `ReAct` station carries no wiki concept. No concept pages were edited.
- Next: decide whether the human-side cluster earns a station or is a deliberate cut; decide separately whether the two absent machine-side failure modes belong in the demo; pin the rows that are decided so future syncs leave them alone.

View File

@@ -1,45 +1,45 @@
# Script coverage
#coverage
## Metadata
- **Script:** `raw/sources/Webinar script.md`
- **Last synced:** 2026-07-28
- **Stations:** Chat box · ReAct · Tools · Memory · Skills · Process · OS
## Coverage
| Concept | Status | Station | Pinned |
|---|---|---|---|
| [[harness]] | covered | Tools | |
| [[evolution-of-agent-tooling]] | covered | Tools | |
| [[skills-as-memory]] | covered | Skills | |
| [[solve-first-then-skillify]] | covered | Skills | |
| [[personal-ai-operating-system]] | covered | OS | |
| [[context-as-scarce-resource]] | partial | Memory | |
| [[agentic-loops]] | partial | Process | |
| [[code-as-throwaway]] | partial | OS | |
| [[levels-of-ai-usage]] | partial | all | |
| [[integration-dead-ends]] | absent | — | |
| [[leave-less-room-for-imagination]] | absent | — | |
| [[product-ownership]] | absent | — | |
| [[connections-as-moat]] | absent | — | |
| [[network-from-a-standing-start]] | absent | — | |
| [[seniority-and-the-junior-squeeze]] | absent | — | |
| [[decoupling-identity-from-profession]] | absent | — | |
| [[think-wider-not-bigger]] | absent | — | |
| [[make-more-cheap-code]] | absent | — | |
| [[enterprise-ai-reality]] | absent | — | |
## Notes
- Eight of the ten absent concepts are human-side or strategy-side, per the grouping in `index.md`. The script's spine is machine-side and it never reaches that material.
- The remaining two absent concepts are machine-side: [[integration-dead-ends]] and [[leave-less-room-for-imagination]]. The script demonstrates the happy path, so it never reaches connector gating or spec ambiguity — the two ways the machine side fails in practice.
- The `ReAct` station carries no wiki concept at all.
- Set `Pinned` to `yes` on any row whose status is a deliberate decision. Sync will not touch it.
## Related Pages
- [[overview]]
- `raw/sources/Webinar script.md`
# Script coverage
#coverage
## Metadata
- **Script:** `raw/sources/Webinar script.md`
- **Last synced:** 2026-07-28
- **Stations:** Chat box · ReAct · Tools · Memory · Skills · Process · OS
## Coverage
| Concept | Status | Station | Pinned |
|---|---|---|---|
| [[harness]] | covered | Tools | |
| [[evolution-of-agent-tooling]] | covered | Tools | |
| [[skills-as-memory]] | covered | Skills | |
| [[solve-first-then-skillify]] | covered | Skills | |
| [[personal-ai-operating-system]] | covered | OS | |
| [[context-as-scarce-resource]] | partial | Memory | |
| [[agentic-loops]] | partial | Process | |
| [[code-as-throwaway]] | partial | OS | |
| [[levels-of-ai-usage]] | partial | all | |
| [[integration-dead-ends]] | absent | — | |
| [[leave-less-room-for-imagination]] | absent | — | |
| [[product-ownership]] | absent | — | |
| [[connections-as-moat]] | absent | — | |
| [[network-from-a-standing-start]] | absent | — | |
| [[seniority-and-the-junior-squeeze]] | absent | — | |
| [[decoupling-identity-from-profession]] | absent | — | |
| [[think-wider-not-bigger]] | absent | — | |
| [[make-more-cheap-code]] | absent | — | |
| [[enterprise-ai-reality]] | absent | — | |
## Notes
- Eight of the ten absent concepts are human-side or strategy-side, per the grouping in `index.md`. The script's spine is machine-side and it never reaches that material.
- The remaining two absent concepts are machine-side: [[integration-dead-ends]] and [[leave-less-room-for-imagination]]. The script demonstrates the happy path, so it never reaches connector gating or spec ambiguity — the two ways the machine side fails in practice.
- The `ReAct` station carries no wiki concept at all.
- Set `Pinned` to `yes` on any row whose status is a deliberate decision. Sync will not touch it.
## Related Pages
- [[overview]]
- `raw/sources/Webinar script.md`