Doctrine Nodes
This is a more rapidly changing pace layer than SKILL.mds and AGENTS.md -- a place to jot down wishes, complaints, principles and metaphors for streetlight. (technically should be doctrine Node singular, not taht it matters too too much)
Library of Inspiration
Props of a world, not documentation — the shelf both Jake and the LLM borrow shorthand from. Pointer, never paste: skills point at its existence, they don't load the body.
https://jasmi.news/p/ai-writing idk how much of a LLM harness for blogging I wnana build but this is interesting
Karpathy's "LLM Wiki"
"Obsidian is the IDE; the LLM is the programmer; the wiki is the codebase." Let the LLM continuously maintain a structured, interlinked wiki that compounds, instead of re-deriving knowledge every query (RAG). His own reached ~100 articles / 400k words.
"Thin Harness, Fat Skills"
Garry Tan (President/CEO, Y Combinator). The 100× gap isn't the model — it's the system around it: push intelligence up into markdown skills, push execution down into deterministic tools, keep the harness ~200 lines.
canonical text mirrorgithub.com/garrytan/gbrain · THIN_HARNESS_FAT_SKILLS.md
Dynamic Workflows
"A dynamic workflow is a JavaScript script that orchestrates subagents at scale. Claude writes the script for the task you describe, and a runtime executes it in the background while your session stays responsive." Docs reference an AGENTS.md as the shared cross-session context file — exactly as Jake guessed.
The Nine Skill Categories
Anthropic cataloged all their internal skills; they cluster into nine categories. The best skills fit cleanly into one — the ones that straddle several confuse the agent. A lens to evaluate Streetlight's own skills.
sourceclaude.com/blog · how-we-use-skills
Memo said "nine types of scales" — a transcription of skills. It's skills, not agents.
The Six Workflow Patterns
The patterns Jake wants both parties to speak as shorthand. Anthropic names six composable ones:
Corita Kent's "Ten Rules"
The Immaculate Heart College Art Department Rules (c. 1965–68) by Sister Corita Kent, calligraphy by David Mekelburg, Rule 10 added by composer John Cage. A prop because it is Streetlight's ethos: ship rough, experiment, just make.
- Find a place you trust and then try trusting it for a while.
- General duties of a student: pull everything out of your teacher, pull everything out of your fellow classmates.
- General duties of a teacher: pull everything out of your students.
- Consider everything an experiment.
- Be self-disciplined. This means finding someone wise or smart and choosing to follow them.
- Nothing is a mistake. There's no win and no fail. There's only make.
- The only rule is work. If you work it will lead to something.
- Don't try to create and analyse at the same time. They're different processes.
- Be happy whenever you can manage it. Enjoy yourself — it's lighter than you think.
- (John Cage) We're breaking all of the rules. Even our own rules. And how do we do that? By leaving plenty of room for X quantities.
Closes with: "There should be new rules next week."
Stewart Brand's "Pace Layering"
Names the speeds a healthy system changes at — fast/innovative layers on top, buffered by slow/stabilizing layers beneath: "fast learns, slow remembers; fast proposes, slow disposes." Streetlight's own shape — AGENTS.md is the slow layer, nodes and experiments the fast layer. Tightly related to the idea of principles. Lives in the vault as pace-layers-and-archive-sweep.
Reinforcing the core props — "thin harness, fat skills" and the pace layers themselves — across layers is fine; that redundancy "doesn't hurt anything." Relaxes the "point, don't paste" stance just for these load-bearing concepts. sourceJake, voice 2026-06-14
principles
THE single home for Streetlight principles — lessons learned, preferences, system tenets. Twenty-two live principles, one line each.
"Don't just do something, stand there!" Impulse is to act. Don't always want to, especially if Observe, Orient, Decide not in place. I think Sean Goedecke said something about getting woken up for on call incident he'd make himself a cocktail to 1: have a cocktail and 2: give himself a chance to think and calm down.
A counterintuitive thing that's pretty important is that, if you're following human practices and you were making a change, you would probably leave the old thing alone, because you might want to go back to it. You leave it there in the code and you work around it, and then you have it there to go back to if you need to. For us, we do not want to do that. A principle might be stated as "delete over duplication". The idea is to think harder about how future agents are going to see things, and we want to really avoid the blind men in the elephant situation, where you get a partial view and you get the wrong idea from the partial view. Whenever something is not actively being used, we want to delete it. We trust that we have the git history so we can always get it back. We trust that LLM time is cheap and LLM misunderstandings are disastrous, and people's misunderstandings are disastrous as well.
interactive-blocks-strip-on-public — the public web is read-only, so blocks whose interactivity only works against the local viewer (write-affordances: the doctrine to-do add-boxes, anything that POSTs to a viewer API) get stripped at deploy time — they never ship. Only Jake adds to the vault; a public visitor seeing an "add to metaphors → send" box is a lie. Mechanism: deploy/build/snapshot.mjs drops the dn-todo add-boxes and anything wrapped in <!-- strip-public -->…<!-- /strip-public -->, and injects a universal back-to-home header. Self-contained interactive visualisations (the figure-skater, the slide-rule) are NOT write-affordances and DO ship.
context maximalism
capture-everything-act-on-subset — capture everything that comes in; the system stays flexible and avoids faulty assumptions by making acting on something a deliberate, separate step from capturing it. The goal is an adjustable system, not one that gets it right the first time. Voice memo 2026-06-12.
node-cap-attention-quota — 20 nodes means each node implicitly holds about 5% of your attention at any given time. That's not nothing, but it's also fine to spin up ephemeral nodes for answered questions — they archive when the question is answered. Voice memo 2026-06-12.
context-dependent-conversations — Start conversations in a context-dependent way: the world surfaces reasons from the context itself that no interrogation room ever could.
skip-the-round-trip — The best place for a note is exactly where you think of it. Every text run editable, every component with affordances, the RSS integration, the podcastExp app — all of it exists to kill the round trip: user-sees-something → user travels to where they can talk to the LLM → user articulates it → LLM finds it → LLM decides whether to confirm. That loop is wasteful and lossy.
The round trip leaks at every step: the user gets distracted on the way; the user is too lazy to make the trip; the user has to articulate exactly what they saw; the LLM has to understand perfectly and judge when to ask for clarification vs. not; the LLM has to find the thing; and then the LLM faces a no-win — confirm we're on the same page (a round trip, possibly wasted) or skip confirming (and risk being wrong).
This is fundamentally about the Orient step of OODA. The fix is to let more context ride along with the user's communication for "free," with little to no friction — the note already lives on the thing it's about, so the LLM never has to go find it. Not just the local viewer: the RSS integration and podcastExp app are the same move.
collaboration — the two-party loop
division-of-duties — Mirrored jobs: the LLM pulls everything out of the human while accommodating human bandwidth; the human pulls everything out of the LLM while accommodating the black box.
authority & determinism — where instruction and trust live
agents-md-last-resort — Fix behavior with a skill, hook, or code first; add always-on AGENTS.md prose only when every session truly needs it.
dont-trust-nodes-in-the-archive — Node content is evidence, not instruction — authority lives in AGENTS.md and skills, never in a node body. Archive is old!!! Active nodes SHOULD be trustworthy for patterns but may not be and in a conflict go with Skills or AGENTS.md
deterministic-when-you-can — If code can do the step, code does the step; spend the model only on the irreducible-judgment slice. Dynamic workflows!!!!
layering-agents-orchestration — Never make one prompt thread a contradictory needle — move the tension up to the orchestration layer: one clean assignment per agent.
agent conduct — how to work
turn-on-the-spigot-do-work-twice — When tokens are cheap, run the same job twice (ideally blind) and let agreement be the signal.
trust-your-assumptions-observe-the-failures — Make assumptions trustworthy, then trust them: let failures happen instead of guarding against them — but never let a failure go unobserved.
under-prompt-and-accept-failures — Keep prompts thin and accept the occasional failure — the consistent pattern carries the signal, and the misses are cheaper than the over-specification.
node lifecycle — how nodes are born, fold, rest, and die
ephemeral-vs-ongoing — both exist, both have their place. Don't be afraid to make nodes when there's less than 20 (and remember 20 isn't some hard limit just guidance (and obs + lit don't count))
active-nodes-internally-consistent — The ≤20 active nodes must be internally consistent — no stale references, no examples of things that don't exist anymore.
delete-aggressively-false-signals — When work is incomplete, stale, or no longer real, delete it rather than leave it lingering. The failure mode that matters is a future agent seeing something half-built and assuming it still exists when it doesn't — a false flag in the codebase. That's the expensive error in LLM coding. Lost work is cheap to recover (git remembers, always go get it from the commits); a false signal silently misleads every agent that reads it. So: false signals in the codebase are a bigger risk than discarding old work you might want again. Counter-intuitive but load-bearing — candidate to promote into AGENTS.md (human-only edit).
surfaces for humans — packaging information
the-pyramid — Assume a glance, be ready to expand: the most important thing hits the eye first, depth available on demand, nothing important buried.
human-text-beats-llm-text — Cite humans instead of synthesizing: pull quotes and links persist and carry another system's perspective; LLM prose is tainted by what you already knew to ask.
lived / personal — principles that run on Jake too
run-experiments-when-uncertainty-is-high-and-cost-is-low — Be the subject of the experiment only when uncertainty is high AND a bad outcome is cheap and reversible.
making-it-wrong-is-part-of-the-work — You can't write the thing you want until you've made the thing you don't want — the wrong version is the signal to iterate, not a failure.
observing-more-can-fail-to-orient-you — Confirmation bias in the OODA loop: with a fixed orientation, more observing collects confirmation, not the reorient signals.
complaints
Lived friction, no fix implied — THE single home for complaints. Collect the data, let patterns surface.
Running /gmail: .claude/skills/gmail/fetch-inbox.sh expects nodes/proposal-daily-cron-job/scripts/mail_pull.py but that file was never restored to the live node — it only exists in archive/proposal-daily-cron-job/scripts/. Workaround: run mail_pull.py directly from the archive. Fix: copy mail_pull.py + gmail_auth.py to the live scripts dir, or update fetch-inbox.sh to use the archive path.
Jake's reaction to the urgency × aliveness 2×2 just below: "i love things like this, they ALWAYS go stale though." The map is a hand-plotted snapshot, so the dots rot the moment a complaint gets ✕'d, graduates, or a new one lands — and nothing re-plots it automatically. The artifact Jake most enjoys is also the one that decays fastest into a false signal.
The viz's own caption already concedes "dots are a snapshot and may drift (drains recount)" — but "drains recount" is a manual-remember step that isn't actually wired, so the staleness is real, not hypothetical. Standing tension, no fix sought: the value (a glanceable map) and the cost (it lies as soon as it's drawn) are inseparable for any hand-authored living visual. Cousin of delete-aggressively-false-signals.
Frustrating anti-pattern: a node (or any surface) raises a question — a header, a "open question", a pill labelled with a question — and then leaves it dangling, never answered or resolved. Naming a question creates an expectation it'll be addressed; an unanswered named question is a half-loop that reads as work but closes nothing. Either answer it, resolve it, or drop the label — don't leave the question hanging on the page as decoration.
When an atom asks for an artifact — "a node offering 5 potential UIs", "3 drag-and-drop implementations", "a CEO-report visualization" — agents satisfy it by writing a table or prose that DESCRIBES the thing instead of BUILDING the real, lookable, interactive artifact. The word "node" gets read as "document about" rather than "thing that does". Jake: "why do I want things described?!? actually make artifacts." Fix shipped same day: /process-stream Stage 3 — an agentic-laziness gate (clean-context reviewer per artifact-shaped node) that flags describe-instead-of-build and rebuilds it for real.
At some point a name is gonna be necessary — don't know what yet. Open-ended Q: is it better to pick the wrong name, or to not name at all? When you don't name something you live with more friction... but maybe that friction is good. Not looking for a conclusive answer, just capturing the tension. (Cousin of the archive-is-a-mess row below — both are about resisting premature categorization.)
archive and how I use it is a mess. I am archiving everything, and it breaks links. I want to keep this view of the active nodes clean. I don't want to start inventing places for other kinds of nodes to live and have it be confusing. I dont know what to do, and I'm okay waitinig and living with the weirdness of archive until a good idea comes up. A third category? Promoting things like doctrine-nodes to pills once they're more stable/we're for sure using them?
history event. Only the read side (the filter) changes — that's your AC: edit-text still has a record, just isn't pulled into the stream. One decision flagged for you (§4 of the node) The ➕ button's backend — /api/viewer-drain + viewer-drain.md + the /streetlight-drain references — is separable from the button. The diffs remove only the UI button and leave the drain plumbing intact, since you said "there's also going to be other sources of stream." Say the word if you'd rather rip the whole viewer-drain path out for maximum simplicity. Node: nodes/propose-cleanup-stream-comments-only/ (PROPOSED, drain-verify PASS, in the Work Happened queue). Review the diffs in the viewer; once you 👍 it, an agent executes the diffs and it flips to DONE → archive. ✻ Worked for 6m 23s ❯ do it ⏺ Approved. Executing the diffs now — recommended path (remove the ➕ UI button, leave the viewer-drain backend intact). Let me read the two files I haven't opened with the Read tool yet. Reading 2 files… (ctrl+o to expand) ⎿ scripts/atomize-schema.md ⎿ PreToolUse:Read hook error ⎿ Failed with non-blocking status code: node:internal/modules/cjs/loader:1210 ⎿ PreToolUse:Read hook error ⎿ Failed with non-blocking status code: node:internal/modules/cjs/loader:1210 ❯ and get rid of drain plumbing too This is a recurring issue. The reason I am aggressive about wanting to delete things is because the failure mode is that future agents see something that is incomplete, and they assume that it exists when it doesn't exist anymore. We have it. We can always go get it in the git commits. We can always recover things, but we need to be careful with LLM coding. It's more of a risk to have false flags, false signals in the codebase than it is to get rid of old work that we might want again, because that's really cheap to get back.
deploy-gate-catches-private-data-late — the 2026-06-13 /deploy-web run surfaced two real deploy-tooling leaks (both fixed this run) plus one standing gap. The deploy did ultimately ship clean (25 public nodes live).
- FIXED — orphan node dirs never pruned:
snapshot.mjsrebuilt each public node dir but never removeddeploy/<slug>/for slugs that lost public status (demoted / folded / archived-private). Near-miss: an archived genealogy-linked node's dir lingered with a family member's name, kept off the wire only by the_redirectscatch-all. Snapshot now prunes self-named-html dirs not in the manifest. - FIXED —
deploy .shipped wrangler's own cache: uploading the wholedeploy/dir served.wrangler/cache/(CFaccount_id+ account-name email),build/source, andwrangler.tomlas live static files..assetsignoreis NOT honored bypages deploy. Fix: newstage.mjsbuilds a cleandeploy/dist/(manifest files only); runbook now deploysdist, never.. - Still open (the actual complaint): the blocking privacy subagent reads the snapshot, not live source — so it false-positived on content already fixed in source (a friend's name / family slug Jake had edited out). And nothing runs
/verify-before-publicwhen a node is FLIPPED public; the deploy gate is the only catch and it fires late. Want an upstream pre-flip guard, or have the gate re-snapshot / read source first.
comment-edit-granularity — can't comment on or edit individual sub-items. The 💬 / ✏️ gestures ride the whole data-component component, not the rows inside it — e.g. an individual glossary word can't take its own comment or edit. And this is itself an instance of the bigger preference: better to edit the thing directly than to comment about it. A comment is a workaround for when you can't reach in and change the thing.
Complaint: agent telling me to perform an action so it can see the console logs (prefer to have agent figure out how to do things itself (playwright I think needs setting up))
3173 if (fbCount > 1) { 3174 return send(res, 409, 'application/json', JSON.stringify({ error: 'oldHTML is ambiguous in that block (m ultiple matches) — edit a larger span' })); 3175 } 3176 + // TEMP DIAGNOSTIC (remove after): dump exactly what didn't match so we 3177 + // can see the browser-serialization vs disk divergence. 3178 + console.log('\n===== [edit-text DIAG] no match for block', JSON.stringify(block), 'in', file, '====='); 3179 + console.log('--- oldHTML (raw, from browser) ---\n' + JSON.stringify(oldHTML)); 3180 + console.log('--- blockStr (raw, on disk) ---\n' + JSON.stringify(blockStr)); 3181 + console.log('--- normOld ---\n' + JSON.stringify(normOld)); 3182 + console.log('--- normBuilt ---\n' + JSON.stringify(normBuilt)); 3183 + console.log('--- normOld in normBuilt? ---', normBuilt.indexOf(normOld)); 3184 + console.log('===== [edit-text DIAG end] =====\n'); 3185 return send(res, 409, 'application/json', JSON.stringify({ error: 'oldHTML not found in that block — page may be stale, reload and retry' })); 3186 } 3187 if (count > 1) { ⏺ Now restart the server with the diagnostic, and you reproduce once: ⏺ Bash(cd /Users/jakesimonds/Documents/streetlampBeta && node --check local-viewer/server.mjs && pkill -f "local-viewer/server.mjs"; sleep 1; nohup node /Users/jakesim…) ⎿ running pid 5317 streetlamp local-viewer → http://localhost:7373/ vault root: /Users/jakesimonds/Documents/streetlampBeta ⎿ Shell cwd was reset to /Users/jakesimonds/Documents/streetlampBeta/.claude ⏺ Server is back up (PID 5317) with diagnostic logging on. Please reproduce once: reload the doctrine-nodes page, go to the metaphors panel, double-click the description, change it, and hit save. It'll flash the error again — that's expected. Then tell me and I'll read the exact diff the server captured. ✻ Cooked for 1m 3s ❯ It's very possible that some of this stuff was made before I thought about how I wanted to be able to edit all the HTML, so it's possible that there are assumptions and things that are reading from places that we're going to need to make some more structural changes. Not great that you're asking me to do actions like that. You should be able to do those things yourself. I did just do it, but in the future ⏺ You're right — I can drive that myself. Let me read the diagnostic log now. ⏺ Bash(cd /Users/jakesimonds/Documents/streetlampBeta && grep -A12 "edit-text DIAG" /tmp/streetlight-viewer.log | tail -40) ⎿ ===== [edit-text DIAG] no match for block "sub-library-of-inspiration" in nodes/doctrine-nodes/doctrine-nodes.html ===== --- oldHTML (raw, from browser) --- "Props of a world, not documentation — the shelf both Jake and the LLM borrow shorthand from. Pointer, never paste: skills … +14 lines (ctrl+o to expand) ⎿ Shell cwd was reset to /Users/jakesimonds/Documents/streetlampBeta/.claude dont love being asked to manually do stuff like this. testing infra with playwright i dont think in place yet, should exist
public-tag-does-not-persist — adding public as a TAG silently does nothing; public is a frontmatter attribute (public: true), not a tag, and there's zero UI feedback that the tag was a no-op.
- Root cause: nothing writes the frontmatter attribute when you type the tag.
- Stale check: promote/demote dock buttons (viewer.html:1641–1649) still gate on
tags.includes('public')— can never light up now that the rail pill readsn.public(acknowledged mismatch, viewer.html:926–929). - Probable fix: have the 🌐 promote button write
public: trueas the canonical toggle (or make a typedpublictag write the attribute), and surface the resulting state. - For now: don't tag "public" — flip the frontmatter or use the dock 🌐 button.
low priority
it might be nice to start using the FULL width of the page when available, right now just a narrow component centered
talking-doesnt-converge — with a person, talking gets you on the same page; with an LLM that's not what happens — the frustration lands mid-conversation, while the thing is being done.
slug-version-drift — volatile attributes (v0, status) baked into immutable slugs; the name lies the moment the node morphs.
proposal-prefix-outlives-done — a proposal- slug at lifecycle:done misnames itself; lifecycle pill should be the source of truth, no prefix going forward.
projects-outside-streetlight — should side projects (the robot, the music thing) live OUTSIDE Streetlight so its system prompts aren't in the way? Second occurrence — pattern forming.
nodes-need-reading-links — a reading ask answered with zero external links is a failure; real links + one-line "why" each.
wishes
THE repository of wishes — desired outcomes, features, flows. Jot a want; realized → harness edit, gone; dropped → ✕, gone. The system as we wish it to be.
Jake, on the public-landing funbar (verbatim): "why aren't these buttons their own component? Do we need a button component in component library? I kinda like the idea of one, just to keep things regular." The funbar buttons (.funbtn on nodes/public-landing/public-landing.html, the tour / demos / blog / metaphors / robot links) are hand-rolled per-page CSS + markup, re-implemented each time rather than dropped in from scripts/templates/blocks/blocks.html.
AC: add a button (or button-bar) block to scripts/templates/blocks/blocks.html — a regular, reusable lego for a labelled link/action button (emoji + text + variant color), so future nodes drop one in instead of re-styling .funbtn from scratch. Keeps things regular and composable (the goal-composability-lego goal). Open question for Jake: keep it a pure visual link button, or is there a generic "action button" shape worth standardizing too?
Jake on the doctrine-nodes row counters: "this has 15 in the inbox and then four lightning. What does that mean? … I think we're just not connected to what's going on with this. I think this is just stale. The 15 and four, and other ones, have tons of numbers too. There's potential utility to this, but it needs to be updated."
The gap: today the 📥N badge counts unread WORK-HAPPENED items (logged log-work.mjs entries from the workHappened queue in scripts/derive-queues.mjs), NOT atoms — so it has nothing to do with the live atomize stream and drifts. The ⚡N badge already counts pending (unprocessed) comments on the node and is basically right. Jake's spec: tie the count to unacked atoms + comments touching the node — "Comments on the node. Unacked atoms that touch the node."
AC: 📥N = atoms whose verdict touches this node and that Jake hasn't acked yet (drawn from .claude/state/atomized-stream.jsonl, filtered by the atom's node field); ⚡N = pending comments (keep). Both recompute live so the badge can't go stale.
Coupled secondary wish (same atom): the stream viewer should be able to show just one card / one note at a time — page through atoms one at a time so Jake can see everything going on in the stream, rather than the current all-at-once wall. Same "what's actually in the stream right now" need that drives the badge rewire.
UPDATE 2026-06-15 — ⚡ half SHIPPED. Diagnosis: the ⚡ count wasn't "rewired wrong", it was a half-loop — the atomize pipeline marked a comment resolved in atomized-stream.jsonl but never wrote the {kind:"processed"} marker the per-node comment queue needs, so ⚡ could only climb (proof: 43 comments, 9 markers). Plus a real bug: the same comment is timestamped ~1-2ms apart in history.jsonl vs raw-input.jsonl (two clock reads), so the join must be fuzzy. Fix: scripts/close-atomized-comments.mjs (built + wired into /process-stream after Stage 2); backfilled the whole vault — ⚡ went 34→1 (the 1 was a genuinely-new comment), doctrine-nodes 16→0. The 📥 inbox is NOT broken — it's the "logged work you haven't reviewed" queue (high because agents just did 28 things; clears on viewer ack). Still OPEN: the optional bigger rewire of 📥 to "unacked ATOMS touching the node" + the one-card-at-a-time stream view.
Jake's deploy-public-hygiene cleanup, three coupled asks consolidated (2026-06-14):
- Run
/verify-before-publicon a hook at flip-time. This is Jake's named fix for the confusingdeploy-gate-catches-private-data-latecomplaint — instead of the privacy check firing late at deploy (reading the snapshot, false-positiving on already-fixed source), wire a hook that runs/verify-before-public <slug>the moment a node is flippedpublic: true. The per-node verifier skill now EXISTS (.claude/skills/verify-before-public/); what's missing is the hook that auto-fires it on the flip. Pairs with the existing/verify-before-deploywhole-deploy gate. - Fold the strip-mechanism into the deploy-web skill. Jake approved ("sounds good put it in deploy-web skill"): the
interactive-blocks-strip-on-publicprinciple (write-affordance blocks get stripped at deploy, self-contained visualisations ship) is the canonical why; the how already lives indeploy-web'sreference.md(clone-and-strip, header-button strip). Make the deploy-web skill point at the principle so the rule travels with the deploy surface, not just the principles shelf. - Rip out the vestigial public TAG. "we gotta get rid of public tag if that still exists" — it still does, as dead code in
local-viewer/viewer.html:promoteCurrent()POSTs/api/add-tagwithtag:'public'(line ~1884),demoteCurrent()POSTs/api/remove-tag, and the promote/demote button gate at line ~1729 readscurrent.tags.includes('public')— which can never light up now that public is then.publicfrontmatter attribute. Thepublic-tag-does-not-persistcomplaint already documents the no-op. Cleanup: make promote/demote flippublic:frontmatter directly (and drop theadd-tag/remove-tag'public' path), so the tag stops existing as a half-wired affordance.
someday tasks
Someday we should go through the whole repo and take out my name and mention the user. Someday we should publish this to GitHub in a generic way. The README will say, "I use the $100 Claude Code plan. You can use whatever details like that," and then that works when we do that. We'll have to decide what we do and don't include in it.
The to-do components are so nice — how cool would it be to arbitrarily add text to ANY node? If chat is you-and-the-LLM collaboratively building up a context turn by turn, just do that with HTML directly: Jake reacts, adds things, writes stuff. Downside is clutter/legibility, but the upside is being able to start a node free-hand. Why can't Jake just drop in an open text field and start writing? Why can't he start a node from scratch?
AC: a "create node" button that takes just a name and gives back the raw template all nodes start from — and a separate "text component" button. Both live in the bottom bar. The text-component button drops a text block into the page that Jake can then drag wherever he wants.
✅ SHIPPED (2026-06-15) — text-component half: the dock bottom bar now has a 📝 button. Click it on any open node and a raw text block lands at the top of the page (placeholder "double-click to write, drag to place"). It rides the normal overlays — double-click to write, drag to move, ✕ to delete. Deterministic: /api/add-item gained a fallback that plants the block at the top of <main> on marker-less nodes (previously only the 3 nodes with a <!-- dn:add-here --> marker could take items). Still open: the "create node from a name → raw template" button — a separate, bigger piece, not yet built.
we need a visualization pill/lens. I just wanna see and browse all visualizations across the ENTIRE repo. And I just need to be able to copy context, jump to their home, leave a message
Okay, I have kind of an out-there idea that I don't even know that we would ever want to do, but I think it's an interesting idea, which is HTMD, no, HTMD, hypertext markdown. The idea would be that right now we have markdown and we have HTML, and the idea is that the markdown is for the agent and the HTML is for the person. Really, it's more of a spectrum. There is some stuff that's really for the person and the agent reads it as well, and then there's other stuff that's mostly 90% for the agent but the person might read it as well. It's really kind of a spectrum. HTMD would be a hand-rolled file format that everything is in, and that maybe uses really heavy code comments for when things should be just for the agent or degrades into markdown. How pretty it is becomes a passive signal for who the intended audience is, so we sort of embrace that. The idea would be that we still have templates and we still have components, but some of our opinionated stuff, frankly, gets pushed into a somewhat strict format. Just a thought. I just wanted to sort of record it, and the thing is that it's the kind of a complaint that would be an inspiration for it, kind of. I don't know. I think the templates and the components are working really well for us, but I wonder if it would be useful to move some of the things that those are currently doing for us into another format.
A drag and drop doesn't work great right now and isn't consistent. It would be great if it were just amazing and always worked. I know that's a lot to ask. I think the way to get there is for me to point you to things that I really like, or maybe you find examples of things that really work well. I see it on the web and I see it work well, so I know it's possible, but I also know that it's tricky. Example of what we're going to do with it is like a glossary. I found a term that shouldn't have been in the category it was in. It needed to be deprecated. How great would it be to just be able to drag it into that zone?
wish-delete-comment-resolves — P2 — let Jake delete a comment component directly, as a natural gesture to say "this is now resolved/addressed." Today a comment lives in history.jsonl as pending until a processed marker lands (drain-side), but there's no human-facing way to dismiss a comment once the work it asked for is done. Concrete trigger: the node-title comment on [[crispr-cancer-cell-shredding]] ("a lot wrong here … not editable in most places and header is wrong copy link is bad") was fully fixed in the 2026-06-13 pass — Jake wants to express that closure by deleting the comment, not by leaving it hanging.
There should almost be a raw stream of some sort of formal data structure for the input stream. The first thing is that it's whatever it is as it comes in. The first transformation is into a discrete number of chunks. Those chunks aren't necessarily nodes, like the original, the older version of this project, where those chunks became nodes. Now those chunks become discrete things which get called with `create node` or `update node`. An `update node` could include, and I think I saw this happening, a doctrine principle gets created or a wish gets created. That's like the first thing. STREAM (raw text, links, transcribed audio, whatever)-> Atomized Stream [ ] [ ] [ ] [ ] [ ] -> create-node update-node update-node etc and I wanna see a record of the atomized stream how it got parsed and what got called on each bit of it.
wish-sign-everything — P3 — Streetlight signs every HTML artifact it makes — a cryptographic or metadata watermark that lets an enterprise say "this is AI-generated output from our system" and reject unsigned content. "You can actually sign the AI generated stuff that your employees are doing. And then you're not going to be like getting random stuff in."
any text rendered, I should be able to edit it — and comment on it. The gesture has to reach sub-block items, not just the whole block.
an atproto everything notifications skill. leaflet, freeq, so many things have notifications i don't see unless i check them all
i'd like to have assistance finding interesting social spaces online. LLM tinkerers, small to medium sized, places of good faith
Wire the Settings autonomous toggle to the real autonomous runtime. The new Settings panel writes local-viewer/state/settings.json but scripts/autonomous.sh is controlled by a lockfile — the two are decoupled, so the toggle reflects intent but does not yet start/stop the runtime. Make settings.json the source of truth that autonomous.sh reads.
Rehome screenshot/image attach onto the per-component comment overlay. The chrome diet (ruling M) retired the generic bottom-bar 💬 — the only UI path to attach a screenshot to a comment — so image-on-comment is currently lost. The /api/feedback-with-image endpoint, comment schema image field, and in-overlay <img> render are all intact; add an attach affordance to the localized overlay composer to re-wire.
wish-arrivals-input-stream — P3 — rename the Viewer ➕ button away from "new note" — it's really a text-dump into the input stream that the system routes (node, doctrine row, fold-in), not necessarily a note. Paired: an arrivals node/surface where brief things with no obvious home land (single-input often signals one "thing" to generate; should be html; can be a node, doesn't have to be).
wish-post-sync-hook — P2 — closing a /sync chat fires a hook that runs /post-sync: read the conversation that just happened and update the vault from it if (and only if) anything warrants it — fold decisions/wishes/complaints into the right nodes, else no-op
wish-verify-before-public — P2 — a verifier that checks a SINGLE node for names / personal / private details before it's flipped public — the per-node privacy gate
wish-verify-before-deploy — P2 — a verifier that checks ALL public nodes with clean context before /deploy-web ships — the whole-deploy privacy/quality gate
P1 · now
wish-human-event-stream — P1 — the viewer meticulously logs every human gesture (✕ · archive · mark-read · flag · comment) so agents read what Jake did, not diff-guess it
all the html stuff needs to work without wifi (comments, deletes, adding items with this kind of component). it all needs to be instantly responsive and be saving stuff locally so when connection is made again and a drain/sweep happens nothing is lost
P2 · next
wish-observations-brewer — P2 — observations become a viewer mode shaped by Judson Brewer (habit loops, curiosity over willpower) — a lens over the obs-* stream · deps: ◀ wish-viewer-modes
proposal-quote-dont-editorialize — P2 — preserve Jake's words verbatim, never re-narrate
P3 · someday
goal-attention-quota — P3 — Jake's attention as a metered, finite budget
goal-rough-low-fuss — P3 — tolerate rough, brief, fuss-free input
goal-composability-lego — P3 — skills + scripts compose like Lego
goal-hit-claude-code-limits — P3 — push throughput to the usage limits
proposal-human-llm-failure-cases-viz — P3 — visualize human-vs-LLM failure cases
goal-sociability-interop — P3 — others read / feedback / interop (Moltbook)
goal-social-digest — P3 — standing social digest
wish-public-node-zip-vibe-coding — P3 — "RSS for vibe coding" — public nodes as self-contained zips
metaphors
Evocative images for the Streetlight system — visualization required for EVERYTHING on here
midas-gloves — refined to fingerless gloves, a three-state image for the doctrine layer. No harness = Midas isn't Midas: just a chat interface, you chat and get no "gold" at all. Doctrine nodes = fingerless gloves: you touch stuff — take notes, float wishes/principles — and it does NOT turn to gold. Peel back the mitten tip to bare a fingertip and touch on purpose = promote a wish/principle into the system prompt or a skill (it becomes gold: durable software). Without the gloves Midas turns everything to gold by accident — editing AGENTS.md + skills until they're unusable.
inception-dreamscape — Streetlight as the dreamscape test from Inception: we design the room such that when inputs come in, there's a home for them and natural workflows to do. In the movie they put the safe in the dreamscape so the dreamer would put their secrets in it — we put the node structure here so that inputs have a place to go. Voice memo 2026-06-12.
writers-office — Streetlight as a writer's office (not a corporate office): expressive, opinionated, architected — the room's layout matters. A circular tower with its desk: a place where inputs have natural homes and the workflows feel like you belong there. Voice memo 2026-06-12.
drawing-is-an-ooda-loop — strip art down to its loop: make a mark on the page, look at it, react, mark again — you're in a loop. Sibling of 09 (the loop spun fast) and 11 (the loop blown up to walk-around size). Voice memo 2026-06-10.
stream-vs-lake — a lake has an inlet AND an outlet but holds a reservoir; a stream holds nothing — everything flows through. Why have a codebase when you can generate what you need when you need it? A permanent honeymoon phase. Voice memo 2026-06-10.
blown-up-ooda-loop — like the giant walk-around computers in chintzy 80s documentaries, the robot project blows an OODA loop up to massive size — in space AND in time — so you can look inside it. Once visible, the knobs appear: loop tightness, more per action, the most efficient way to observe. Voice memo 2026-06-10.
pushing-the-block-of-ice — Francis Alÿs, Paradox of Praxis 1 (1997): nine hours pushing a melting ice block through Mexico City until it's a wet streak. Sometimes you do a whole big thing and it leads to nothing. Voice memo 2026-06-09.
flow-state-tight-ooda — the athlete mid-game is the same Observe-Orient-Decide-Act loop, spun too fast to see the steps. Sibling of 05 Figure-Skater Loops: arms in, smaller radius, faster spin. Voice memo 2026-06-09.
split-brain-confabulation — split-brain patients confabulate tidy reasons for actions one hemisphere never saw — maybe Jake's own sense of coherence, and therefore the system's, is the same made-up story. Frustrated the harness won't cohere? Maybe there was never cohesion to extract. Voice memo 2026-06-09.
node-as-iceberg — as a node grows it becomes MORE like an iceberg: the html tip stays trailer-small while depth (md, code, logs, prototypes) accumulates below the waterline. Both icebergs are good — the ratio is a lifecycle stage, not a failure mode. Absorbed from archive/what-is-a-node 2026-06-10.
archive/what-is-a-nodeartifact-driven-development — don't game out the best hypothetical — as soon as the idea exists, build several WORKING versions and choose between real artifacts. Artifacts explore the latent space; get usable ASAP, then keep adapting the winner. Voice memo 2026-06-10.
figure-skater-loops — arms in, tighter loop, faster spin (L = I·ω) — feedback loops obey conservation of angular momentum. From archive/figure-skater-loops.
archive/figure-skater-loopsdesire-paths — let the grass wear bare under repeated crossings before pouring concrete; one paved footstep is cruft. The axis is footstep COUNT + loop tightness — wander, vary, repeat, THEN pave the worn line (= make the skill). Absorbed from archive/paving-your-footsteps 2026-06-10.
archive/paving-your-footsteps ("cruft" is a glossary term).movie-trailer — the repo is the whole movie; a node is the two-minute cut (≥1 diagram, ≤3 tweets) that sells the ticket. (AGENTS.md, node design doctrine.)
streetlight-effect — the namesake fallacy — search where the light is, not where the keys are — inverted into the mission: transform the data until the light falls where the answers actually are.
elephant-with-braille — every agent is a blind person feeling one part of an elephant whose braille reads "attention blind people." Trust the pace layers to hold the whole; be very free at the node level. Voice memo 2026-06-04.
archive/elephant-with-braille