From 0f3b8def66e59876654a8f7b5ad0e475f6298234 Mon Sep 17 00:00:00 2001 From: eggmasonvalue Date: Sat, 5 Sep 2026 23:32:23 +0530 Subject: [PATCH 1/4] cosmetic: redesign startup header with neoclassical portico and banknote branding --- extensions/startup-header.ts | 182 ++++++++++++++++++++++++----------- 1 file changed, 128 insertions(+), 54 deletions(-) diff --git a/extensions/startup-header.ts b/extensions/startup-header.ts index 1e0f183..da7986b 100644 --- a/extensions/startup-header.ts +++ b/extensions/startup-header.ts @@ -4,85 +4,159 @@ import type { } from "@earendil-works/pi-coding-agent"; import { truncateToWidth } from "@earendil-works/pi-tui"; -const WIDE_HEADER_WIDTH = 50; -const COMPACT_HEADER_WIDTH = 38; +const WIDE_HEADER_WIDTH = 42; +const COMPACT_HEADER_WIDTH = 34; function fit(lines: string[], width: number): string[] { return lines.map((line) => truncateToWidth(line, width, "")); } -function renderWide(theme: Theme, width: number): string[] { - const border = (text: string) => theme.fg("borderMuted", text); - const ink = (text: string) => theme.fg("text", text); - const copy = (text: string) => theme.fg("muted", text); +function renderWide(theme: Theme, width: number, expanded: boolean): string[] { + const g = (text: string) => theme.fg("success", text); + const gold = (text: string) => theme.fg("warning", text); const mark = (text: string) => theme.fg("accent", text); + const ink = (text: string) => theme.bold(theme.fg("text", text)); + const tree = (text: string) => theme.fg("dim", text); + const copy = (text: string) => theme.fg("muted", text); - return fit( - [ - "", - border("┌─────────────────────┐"), - `${border("│")} ${ink(theme.bold("FORM 10-K · ITEM 7"))} ${border("◢│")}`, - `${border("│")} ${copy("━━━━━━━━━━━━━━━ ")} ${border("│")} ${mark("┏")}`, - `${border("│")} ${copy("━━━━━━━━━━ ")} ${border("│")} ${mark("┃")} ${ink(theme.bold("S E C S T A C K"))}`, - `${border("│")} ${mark("███████████████")} ${border("│")}${mark("━━┫━━")} ${mark(theme.bold("EVIDENCE → JUDGMENT"))}`, - `${border("│")} ${copy("━━━━━━━━━━━━━━━━ ")} ${border("│")} ${mark("┃")}`, - `${border("│")} ${copy("━━━━━━━━━━━ ")} ${border("│")} ${mark("┗")}`, - border("└─────────────────────┘"), - "", - ], - Math.min(width, WIDE_HEADER_WIDTH), - ); + const corner = `${g("[")}${gold("$")}${g("]")}`; + const billTop = `${g("╔═")}${corner}${g("════════════════")}${corner}${g("═╗")}`; + const billMid = `${g("║")} ${ink("SECSTACK")} ${g("║")}`; + const billBot = `${g("╚═")}${corner}${g("════════════════")}${corner}${g("═╝")}`; + + const lines = [ + "", + ` ${mark("▄█▄")}`, + ` ${mark("┌─────┐")} ${billTop}`, + ` ${mark("│ ")}${gold("█ █")}${mark(" │")} ${billMid}`, + ` ${mark("┌┴─────┴┐")} ${billBot}`, + ` ${mark("▀▀▀▀▀▀▀▀▀▀▀")}`, + ]; + + if (expanded) { + if (width >= 62) { + lines.push( + "", + ` ${tree("Research Pipeline:")}`, + ` ${tree("├─ ")}${theme.fg("mdCode", "[EDGAR]")} ${copy("10-K · 10-Q · 8-K · XBRL statements · Proxies")}`, + ` ${tree("├─ ")}${gold("[SIGNALS]")} ${copy("Form 4 insider buys · Schedule 13D blockholders")}`, + ` ${tree("├─ ")}${mark("[MARKET]")} ${copy("Live quotes · Comps · Earnings call transcripts")}`, + ` ${tree("├─ ")}${theme.fg("mdHeading", "[ANALYSIS]")} ${copy("Forensic MD&A · Unit economics · Margin of safety")}`, + ` ${tree("└─ ")}${theme.fg("syntaxType", "[VIC PITCH]")} ${copy("Norbert Lou numbers-first stock pitch")}`, + ); + } else { + lines.push( + "", + ` ${tree("Research Pipeline:")}`, + ` ${tree("├─ ")}${theme.fg("mdCode", "[EDGAR]")} ${copy("10-K · 10-Q · 8-K · Proxies")}`, + ` ${tree("├─ ")}${gold("[SIGNALS]")} ${copy("Form 4 insider buys · 13D")}`, + ` ${tree("├─ ")}${mark("[MARKET]")} ${copy("Quotes · Comps · Transcripts")}`, + ` ${tree("├─ ")}${theme.fg("mdHeading", "[ANALYSIS]")} ${copy("Forensic MD&A · Valuation")}`, + ` ${tree("└─ ")}${theme.fg("syntaxType", "[VIC PITCH]")} ${copy("Norbert Lou VIC pitch")}`, + ); + } + } + + lines.push(""); + return fit(lines, width); } -function renderCompact(theme: Theme, width: number): string[] { - const border = (text: string) => theme.fg("borderMuted", text); - const ink = (text: string) => theme.fg("text", text); - const copy = (text: string) => theme.fg("muted", text); +function renderCompact(theme: Theme, width: number, expanded: boolean): string[] { + const g = (text: string) => theme.fg("success", text); + const gold = (text: string) => theme.fg("warning", text); const mark = (text: string) => theme.fg("accent", text); + const ink = (text: string) => theme.bold(theme.fg("text", text)); + const tree = (text: string) => theme.fg("dim", text); + const copy = (text: string) => theme.fg("muted", text); - return fit( - [ - "", - `${border("┌───────────────┐")} ${ink(theme.bold("SECSTACK"))}`, - `${border("│")} ${ink(theme.bold("10-K · ITEM 7"))} ${border("◢│")}`, - `${border("│")} ${copy("━━━━━━━━━━ ")} ${border("│")} ${mark("┓")}`, - `${border("│")} ${mark("██████████")} ${border("│")}${mark("━━┫")}`, - `${border("│")} ${copy("━━━━━━━━━━━━ ")} ${border("│")} ${mark("┛")}`, - `${border("└───────────────┘")} ${mark("EVIDENCE → JUDGMENT")}`, + const corner = `${g("[")}${gold("$")}${g("]")}`; + const billTop = `${g("╔")}${corner}${g("═══════════")}${corner}${g("╗")}`; + const billMid = `${g("║")} ${ink("SECSTACK")} ${g("║")}`; + const billBot = `${g("╚")}${corner}${g("═══════════")}${corner}${g("╝")}`; + + const lines = [ + "", + ` ${mark("▄█▄")}`, + ` ${mark("┌─────┐")} ${billTop}`, + ` ${mark("│ ")}${gold("█ █")}${mark(" │")} ${billMid}`, + ` ${mark("┌┴─────┴┐")} ${billBot}`, + ` ${mark("▀▀▀▀▀▀▀▀▀▀▀")}`, + ]; + + if (expanded) { + lines.push( "", - ], - Math.min(width, COMPACT_HEADER_WIDTH), - ); + ` ${tree("Research Pipeline:")}`, + ` ${tree("├─ ")}${theme.fg("mdCode", "[EDGAR]")} ${copy("10-K/Q/8-K · Proxies")}`, + ` ${tree("├─ ")}${gold("[SIGNALS]")} ${copy("Form 4 · 13D")}`, + ` ${tree("├─ ")}${mark("[MARKET]")} ${copy("Quotes · Calls")}`, + ` ${tree("├─ ")}${theme.fg("mdHeading", "[ANALYSIS]")} ${copy("MD&A · DCF")}`, + ` ${tree("└─ ")}${theme.fg("syntaxType", "[VIC PITCH]")} ${copy("Norbert Lou pitch")}`, + ); + } + + lines.push(""); + return fit(lines, width); } -function renderNarrow(theme: Theme, width: number): string[] { - const ink = (text: string) => theme.fg("text", text); - const mark = (text: string) => theme.fg("accent", text); +function renderNarrow(theme: Theme, width: number, expanded: boolean): string[] { + const g = (text: string) => theme.fg("success", text); + const gold = (text: string) => theme.fg("warning", text); + const ink = (text: string) => theme.bold(theme.fg("text", text)); + const copy = (text: string) => theme.fg("muted", text); + const tree = (text: string) => theme.fg("dim", text); - return fit( - [ - "", - ink(theme.bold("SECSTACK")), - `${mark("▰")} ${ink("10-K · ITEM 7")} ${mark("→")} ${mark(theme.bold("JUDGMENT"))}`, + const corner = `${g("[")}${gold("$")}${g("]")}`; + const lines = [ + "", + `${corner} ${ink("SECSTACK")} ${corner}`, + copy("Bottom-Up Equity Research"), + ]; + + if (expanded) { + lines.push( "", - ], - width, - ); + tree("• EDGAR Filings (10-K/Q/8-K)"), + tree("• Signals (Form 4/13D)"), + tree("• Market & Transcripts"), + tree("• Analysis & Valuation"), + tree("• Norbert Lou VIC Pitch"), + ); + } + + lines.push(""); + return fit(lines, width); } -export function renderStartupHeader(theme: Theme, width: number): string[] { - if (width >= WIDE_HEADER_WIDTH) return renderWide(theme, width); - if (width >= COMPACT_HEADER_WIDTH) return renderCompact(theme, width); - return renderNarrow(theme, width); +export function renderStartupHeader( + theme: Theme, + width: number, + expanded: boolean = false, +): string[] { + if (width >= WIDE_HEADER_WIDTH) return renderWide(theme, width, expanded); + if (width >= COMPACT_HEADER_WIDTH) return renderCompact(theme, width, expanded); + return renderNarrow(theme, width, expanded); } export default function startupHeaderExtension(pi: ExtensionAPI) { pi.on("session_start", (_event, ctx) => { if (ctx.mode !== "tui") return; - ctx.ui.setHeader((_tui, theme) => ({ - render: (width) => renderStartupHeader(theme, width), + let expanded = false; + + ctx.ui.setHeader((tui, theme) => ({ + render: (width) => renderStartupHeader(theme, width, expanded), invalidate() {}, + setExpanded(value: boolean) { + if (expanded === value) return; + expanded = value; + tui.requestRender(); + }, })); }); + + pi.on("session_shutdown", (_event, ctx) => { + if (ctx.mode !== "tui") return; + ctx.ui.setHeader(undefined); + }); } From c1379c71fefc427979c4773f1bd161da3114ae8a Mon Sep 17 00:00:00 2001 From: eggmasonvalue Date: Sat, 5 Sep 2026 23:36:36 +0530 Subject: [PATCH 2/4] feat(bootstrap): configure quietStartup in profile settings --- README.md | 4 ++-- context/MAP.md | 16 ++++++++-------- scripts/bootstrap.mjs | 6 +++++- 3 files changed, 15 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index 0312477..af073d9 100644 --- a/README.md +++ b/README.md @@ -28,8 +28,8 @@ From Bash, bootstrap the profile with one command: ``` The bootstrap is safe to rerun. It installs the unpinned top-level Pi package sources, -merges only SecStack-managed package entries and shell-path configuration into the -SecStack profile's `settings.json` and creates a profile-local Python environment. It links the +merges only SecStack-managed package entries, shell-path configuration, and `quietStartup` +preference into the SecStack profile's `settings.json` and creates a profile-local Python environment. It links the profile's `SYSTEM.md` to the installed SecStack package, so `pi update --extensions` updates the research-agent identity and prompt envelope. It does not install coding-task guidance or link global `AGENTS.md` or `APPEND_SYSTEM.md` files into the profile. diff --git a/context/MAP.md b/context/MAP.md index f8130f8..b482163 100644 --- a/context/MAP.md +++ b/context/MAP.md @@ -35,16 +35,16 @@ The bootstrap configures the isolated profile at `~/.pi/secstack-agent`. Its - `agent-browser`. Pi installs and updates each source independently. The bootstrap manages only those package -entries, the profile's Pi-managed shell path, the profile-local Python environment, and a -relative `SYSTEM.md` symlink into the installed SecStack package. The system-prompt-viewer -package is the sole owner of the `/system-context` overlay. SecStack's +entries, the profile's Pi-managed shell path, the `quietStartup` preference, the profile-local +Python environment, and a relative `SYSTEM.md` symlink into the installed SecStack package. The +system-prompt-viewer package is the sole owner of the `/system-context` overlay. SecStack's `restore-tool-envelope` extension restores Pi's live tool snippets and guidelines after `SYSTEM.md` replaces Pi's coding-agent identity. Its `startup-header` extension replaces -Pi's built-in header with a responsive, theme-adaptive SecStack research mark. Coding-task -guidance files are not linked, and the filtered `pi-setup` package contributes no skills, -including `repo-nav` and `bootstrap-docs`. Research runs in the primary Pi context; -no sub-agent package is installed. Authentication, model selection, provider configuration, -sessions, and unrelated settings remain profile-local and untouched. +Pi's built-in header with a responsive, theme-adaptive SecStack research mark and interactive +research pipeline. Coding-task guidance files are not linked, and the filtered `pi-setup` package +contributes no skills, including `repo-nav` and `bootstrap-docs`. Research runs in the primary +Pi context; no sub-agent package is installed. Authentication, model selection, provider +configuration, sessions, and unrelated settings remain profile-local and untouched. ## Skill internals diff --git a/scripts/bootstrap.mjs b/scripts/bootstrap.mjs index b8116d0..eae4218 100644 --- a/scripts/bootstrap.mjs +++ b/scripts/bootstrap.mjs @@ -4,7 +4,7 @@ * SecStack profile. * * This script deliberately changes only the SecStack profile's package list, - * shell command prefix, and optional Bash launcher. + * shell command prefix, quietStartup setting, and optional Bash launcher. */ import { execFileSync } from "node:child_process"; import { @@ -151,6 +151,10 @@ function mergeSettings() { : pathCommand; } + // Silence Pi's default startup banner and raw resource listing so SecStack's + // custom startup header and interactive capability pipeline take center stage. + settings.quietStartup = true; + const temp = join(agentDir, `.settings.${process.pid}.tmp`); writeFileSync(temp, `${JSON.stringify(settings, null, 2)}\n`, "utf8"); renameSync(temp, settingsPath); From bd2c8d9754217b7e91b31bbf78047b3d6174a56b Mon Sep 17 00:00:00 2001 From: eggmasonvalue Date: Sat, 5 Sep 2026 23:52:22 +0530 Subject: [PATCH 3/4] feat(ui): show research pipeline by default and collapse on tool expansion --- extensions/startup-header.ts | 34 +++++++++++++++++++--------------- 1 file changed, 19 insertions(+), 15 deletions(-) diff --git a/extensions/startup-header.ts b/extensions/startup-header.ts index da7986b..5472dd3 100644 --- a/extensions/startup-header.ts +++ b/extensions/startup-header.ts @@ -11,7 +11,7 @@ function fit(lines: string[], width: number): string[] { return lines.map((line) => truncateToWidth(line, width, "")); } -function renderWide(theme: Theme, width: number, expanded: boolean): string[] { +function renderWide(theme: Theme, width: number, showPipeline: boolean): string[] { const g = (text: string) => theme.fg("success", text); const gold = (text: string) => theme.fg("warning", text); const mark = (text: string) => theme.fg("accent", text); @@ -33,7 +33,7 @@ function renderWide(theme: Theme, width: number, expanded: boolean): string[] { ` ${mark("▀▀▀▀▀▀▀▀▀▀▀")}`, ]; - if (expanded) { + if (showPipeline) { if (width >= 62) { lines.push( "", @@ -61,7 +61,7 @@ function renderWide(theme: Theme, width: number, expanded: boolean): string[] { return fit(lines, width); } -function renderCompact(theme: Theme, width: number, expanded: boolean): string[] { +function renderCompact(theme: Theme, width: number, showPipeline: boolean): string[] { const g = (text: string) => theme.fg("success", text); const gold = (text: string) => theme.fg("warning", text); const mark = (text: string) => theme.fg("accent", text); @@ -83,7 +83,7 @@ function renderCompact(theme: Theme, width: number, expanded: boolean): string[] ` ${mark("▀▀▀▀▀▀▀▀▀▀▀")}`, ]; - if (expanded) { + if (showPipeline) { lines.push( "", ` ${tree("Research Pipeline:")}`, @@ -99,7 +99,7 @@ function renderCompact(theme: Theme, width: number, expanded: boolean): string[] return fit(lines, width); } -function renderNarrow(theme: Theme, width: number, expanded: boolean): string[] { +function renderNarrow(theme: Theme, width: number, showPipeline: boolean): string[] { const g = (text: string) => theme.fg("success", text); const gold = (text: string) => theme.fg("warning", text); const ink = (text: string) => theme.bold(theme.fg("text", text)); @@ -113,7 +113,7 @@ function renderNarrow(theme: Theme, width: number, expanded: boolean): string[] copy("Bottom-Up Equity Research"), ]; - if (expanded) { + if (showPipeline) { lines.push( "", tree("• EDGAR Filings (10-K/Q/8-K)"), @@ -131,25 +131,29 @@ function renderNarrow(theme: Theme, width: number, expanded: boolean): string[] export function renderStartupHeader( theme: Theme, width: number, - expanded: boolean = false, + showPipeline: boolean = true, ): string[] { - if (width >= WIDE_HEADER_WIDTH) return renderWide(theme, width, expanded); - if (width >= COMPACT_HEADER_WIDTH) return renderCompact(theme, width, expanded); - return renderNarrow(theme, width, expanded); + if (width >= WIDE_HEADER_WIDTH) return renderWide(theme, width, showPipeline); + if (width >= COMPACT_HEADER_WIDTH) return renderCompact(theme, width, showPipeline); + return renderNarrow(theme, width, showPipeline); } export default function startupHeaderExtension(pi: ExtensionAPI) { pi.on("session_start", (_event, ctx) => { if (ctx.mode !== "tui") return; - let expanded = false; + let showPipeline = true; ctx.ui.setHeader((tui, theme) => ({ - render: (width) => renderStartupHeader(theme, width, expanded), + render: (width) => renderStartupHeader(theme, width, showPipeline), invalidate() {}, - setExpanded(value: boolean) { - if (expanded === value) return; - expanded = value; + setExpanded(toolsExpanded: boolean) { + // Invert: when tools are expanded for deeper inspection, collapse the + // header to yield vertical screen space. When tools are collapsed, + // show the full research capability pipeline. + const next = !toolsExpanded; + if (showPipeline === next) return; + showPipeline = next; tui.requestRender(); }, })); From 736ce5453f47e7fc34d88e00c4c15a5a351df174 Mon Sep 17 00:00:00 2001 From: eggmasonvalue Date: Sun, 6 Sep 2026 00:10:01 +0530 Subject: [PATCH 4/4] feat(ui): improve research pipeline copy across responsive tiers --- extensions/startup-header.ts | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/extensions/startup-header.ts b/extensions/startup-header.ts index 5472dd3..bc99cdd 100644 --- a/extensions/startup-header.ts +++ b/extensions/startup-header.ts @@ -34,25 +34,25 @@ function renderWide(theme: Theme, width: number, showPipeline: boolean): string[ ]; if (showPipeline) { - if (width >= 62) { + if (width >= 77) { lines.push( "", ` ${tree("Research Pipeline:")}`, - ` ${tree("├─ ")}${theme.fg("mdCode", "[EDGAR]")} ${copy("10-K · 10-Q · 8-K · XBRL statements · Proxies")}`, - ` ${tree("├─ ")}${gold("[SIGNALS]")} ${copy("Form 4 insider buys · Schedule 13D blockholders")}`, - ` ${tree("├─ ")}${mark("[MARKET]")} ${copy("Live quotes · Comps · Earnings call transcripts")}`, - ` ${tree("├─ ")}${theme.fg("mdHeading", "[ANALYSIS]")} ${copy("Forensic MD&A · Unit economics · Margin of safety")}`, - ` ${tree("└─ ")}${theme.fg("syntaxType", "[VIC PITCH]")} ${copy("Norbert Lou numbers-first stock pitch")}`, + ` ${tree("├─ ")}${gold("[SIGNALS]")} ${copy("Insider clusters · 13D blocks · Market screens · Themes")}`, + ` ${tree("├─ ")}${theme.fg("mdCode", "[EDGAR]")} ${copy("10-K/Q/8-K · XBRL financials · 13F holders · Proxies")}`, + ` ${tree("├─ ")}${mark("[MARKET]")} ${copy("Live quotes · Peer comps · Trailing returns · Transcripts")}`, + ` ${tree("├─ ")}${theme.fg("mdHeading", "[ANALYSIS]")} ${copy("Normalized FCFF · Reverse DCF / EPV · Moats · Pre-mortem")}`, + ` ${tree("└─ ")}${theme.fg("syntaxType", "[VIC PITCH]")} ${copy("Norbert Lou VIC style · Hard arithmetic · Falsification")}`, ); } else { lines.push( "", ` ${tree("Research Pipeline:")}`, - ` ${tree("├─ ")}${theme.fg("mdCode", "[EDGAR]")} ${copy("10-K · 10-Q · 8-K · Proxies")}`, - ` ${tree("├─ ")}${gold("[SIGNALS]")} ${copy("Form 4 insider buys · 13D")}`, - ` ${tree("├─ ")}${mark("[MARKET]")} ${copy("Quotes · Comps · Transcripts")}`, - ` ${tree("├─ ")}${theme.fg("mdHeading", "[ANALYSIS]")} ${copy("Forensic MD&A · Valuation")}`, - ` ${tree("└─ ")}${theme.fg("syntaxType", "[VIC PITCH]")} ${copy("Norbert Lou VIC pitch")}`, + ` ${tree("├─ ")}${gold("[SIGNALS]")} ${copy("Insider clusters · 13Ds · Screens")}`, + ` ${tree("├─ ")}${theme.fg("mdCode", "[EDGAR]")} ${copy("10-K/Q/8-K · XBRL · 13F holders")}`, + ` ${tree("├─ ")}${mark("[MARKET]")} ${copy("Quotes · Peer comps · Transcripts")}`, + ` ${tree("├─ ")}${theme.fg("mdHeading", "[ANALYSIS]")} ${copy("Normalized FCFF · DCF · Pre-mortem")}`, + ` ${tree("└─ ")}${theme.fg("syntaxType", "[VIC PITCH]")} ${copy("Norbert Lou VIC pitch · Math")}`, ); } } @@ -87,10 +87,10 @@ function renderCompact(theme: Theme, width: number, showPipeline: boolean): stri lines.push( "", ` ${tree("Research Pipeline:")}`, - ` ${tree("├─ ")}${theme.fg("mdCode", "[EDGAR]")} ${copy("10-K/Q/8-K · Proxies")}`, - ` ${tree("├─ ")}${gold("[SIGNALS]")} ${copy("Form 4 · 13D")}`, - ` ${tree("├─ ")}${mark("[MARKET]")} ${copy("Quotes · Calls")}`, - ` ${tree("├─ ")}${theme.fg("mdHeading", "[ANALYSIS]")} ${copy("MD&A · DCF")}`, + ` ${tree("├─ ")}${gold("[SIGNALS]")} ${copy("Insiders · 13Ds · Screens")}`, + ` ${tree("├─ ")}${theme.fg("mdCode", "[EDGAR]")} ${copy("10-K/Q · XBRL · 13F")}`, + ` ${tree("├─ ")}${mark("[MARKET]")} ${copy("Quotes · Comps · Calls")}`, + ` ${tree("├─ ")}${theme.fg("mdHeading", "[ANALYSIS]")} ${copy("FCFF · DCF · Moats")}`, ` ${tree("└─ ")}${theme.fg("syntaxType", "[VIC PITCH]")} ${copy("Norbert Lou pitch")}`, ); } @@ -116,10 +116,10 @@ function renderNarrow(theme: Theme, width: number, showPipeline: boolean): strin if (showPipeline) { lines.push( "", - tree("• EDGAR Filings (10-K/Q/8-K)"), - tree("• Signals (Form 4/13D)"), + tree("• Signals & Discovery"), + tree("• EDGAR Filings & 13F"), tree("• Market & Transcripts"), - tree("• Analysis & Valuation"), + tree("• Bottom-Up Valuation"), tree("• Norbert Lou VIC Pitch"), ); }