HilltopCommand Center
Generated 2026-06-14 22:33 CDT ← Operational dashboard

Memory tiers 4 stores

Three layers Claude reads from on every session, plus the behavioral rules that shape every reply. Tap to expand.
Mutable working state
What's true RIGHT NOW
4h ago
↳ hmg-ops
298 LOG entries

PRIMER, BLOCKERS, CHARTER, OBJECTIVES, LOG. The single source of truth for current operational state. Read on every Claude session.

PRIMER.mdBLOCKERS.mdCHARTER.mdOBJECTIVES.mdLOG.md
Domain knowledge
How HMG ops actually work
2d ago
↳ hmg-ops/runbooks + scripts + state.sqlite
14 runbooks · 53 scripts · state.sqlite

Operational mechanics: how prospecting works, how outreach is reviewed, how the morning stack runs. Plus the live state.sqlite database backing the pipeline.

M5-CUTOVER-PACKET.mdREADME.mdclaude-code-autonomous-ops-deep-report.mdescalation-policy.mdm5-continuity-cutover.mdmemory-routing.mdmorning-stack.mdnew-prospect-intake.mdoutreach-review.mdsend-pipeline.mdsite-update.mdstall-detection.mdweekly-metrics.mdworkspace-organization.md
Durable knowledge
Strategy, people, firms, frameworks
16m ago
↳ Obsidian Brain
294 markdown files

Long-lived knowledge that doesn't change session to session: prospect dossiers, firm intelligence, strategy notes, frameworks. Indexed by MEMORY.md at the vault root.

.claude00-meta_archiveclaude-configclaude-projectshmgprospect-stackroundup
Behavioral rules
How Claude is told to behave
5d ago
↳ auto-memory
54 memory files · 29 feedback rules

Behavioral feedback loaded into every Claude session. Tells Claude how to behave (e.g., verify before quoting, default to Telegram replies, design quality bar).

MEMORYREADMEfeedback-10am-send-cron-canceledfeedback-14d-gate-first-touch-onlyfeedback-build-meta-canary-not-just-step-canariesfeedback-codex-review-touch-scriptsfeedback-daily-updates-into-morning-pdffeedback-ddg-not-brave-for-hmg-searchfeedback-default-to-telegram-replyfeedback-design-bar-client-readyfeedback-execute-without-permissionfeedback-hmg-positioningfeedback-no-codex-without-approvalfeedback-no-hands-faces-in-ai-imageryfeedback-no-outbound-emails-at-allfeedback-no-side-effecting-poll-loopsfeedback-no-stitchfeedback-parallel-subagent-defaultfeedback-portable-paths-for-codex-messagesfeedback-repo-visibility-default-privatefeedback-save-durable-facts-immediatelyfeedback-scope-selectorfeedback-screenshot-per-stepfeedback-self-healing-errorsfeedback-self-improving-skillsfeedback-telegram-no-markdown-around-urlsfeedback-telegram-status-emojifeedback-transient-viz-defaultfeedback-verify-before-quoting-statefeedback-verify-rendered-artifacts-not-just-filterfeedback-watch-skill-for-videoshmg-dashboard-two-prospect-datasetsproject-b012-cowork-task-bypasses-pause-flagproject-burke-resellerproject-claude-code-autonomous-ops-deep-reportproject-claude-code-desktop-2026-05-02project-design-pipeline-three-toolproject-firehose-is-discovery-shadowproject-granite-harbor-capital-buildoutproject-hmg-pipeline-stalled-2026-05-03project-hmg-thin-pool-canary-is-often-a-render-bugproject-lake-effect-sweetsproject-local-llm-m5-researchproject-mac-m5-migrationproject-prospecting-live-vs-dead-engineproject-prospecting-name-extraction-bugproject-revenue-streams-portfolioproject-run-businesses-hmg-agent-wrong-sourcesreference-browser-harnessreference-claude-video-watchreference-hmg-launchpadreference-huashu-design-skillreference-obsidian-mcpuser-anthropic-subscription

Open blockers 7 open · last verified per blocker

Each blocker shows when its verify command last ran. Tap to expand the full unblock plan and trigger Telegram actions.
B-012 🔴 HARD STOP
10 AM Mon-Fri send cron CANCELED INDEFINITELY by Dan
⚠ no verify rule 5d ago
  • Since: 2026-05-12 09:56 CT
  • Action taken: commented out `0 10 * * 1-5 ... send_daily_batch.py` in crontab; backup at `/tmp/crontab.bak.20260512-095612`
  • Rule: do NOT re-enable, do NOT propose a replacement cron, do NOT route sends through any other scheduled path without explicit "go" from Dan in writing. The cancellation is not infrastructure pause (B-008 / send-quality); it's a directive from Dan.
  • Downstream impact: 9:55 materialize step and 11:00 send-rate canary are now no-ops; they're harmless and stay in place until Dan says otherwise. Drafts continue to accumulate but DO NOT SEND.
  • What unblocks: explicit "re-enable the 10 AM send" from Dan. Until then, treat any send as gated 🔴.
  • **⚠️ 2026-06-04 — BREACH FOUND + RE-ENFORCED (Claude, operator-mode, ESCALATED to Dan).** The crontab comment did NOT fully enforce B-012. The active `send_daily_batch.py` filename was silently restored ~5/19 (undoing the 5/12 `.DISABLED` rename), re-arming the **Cowork scheduled task**, which sent **83 real Graph emails 5/12→6/3** (incl. 9 on 6/3, 1 on 6/1, 2 on Sun 5/31) — on days the sweep reported "frozen." The WSL `send-pause.flag` is honored by the canonical copy but NOT by the Cowork runner (different `Path.home()`); 25+ worktree copies lack the flag guard entirely. **Re-applied the proven filename-disable:** `send_daily_batch.py` → `send_daily_batch.py.DISABLED-2026-06-04-b012-reenforce` (reversible). Sends halted 07:42 CT. **Still gated on Dan:** kill/fix the Cowork scheduled task at source so it can't re-arm; before ANY future re-enable, the Cowork runner must honor a kill switch in its own runtime. See LOG 2026-06-04 07:44.
No automated verify rule — resolves only on human confirmation.
B-011 OPEN
B-011
⚠ no verify rule 5d ago
  • Since: 2026-05-06 · One-pager drafted 2026-05-11
  • Doc: `~/hmg-ops/outputs/b011-fidelity-custody-pivot-2026-05-11.md`
  • What's drafted: (1) custody-screen question for Discovery Gap Analysis with 4-route routing matrix; (2) Fidelity-pivot positioning (operational consolidation across 3 liquidity tiers + treasury policy hygiene + custody-agnostic execution); (3) Fidelity-specific touch-1 variant; (4) `custodian` column schema for state.sqlite + sequence_follow_up.py routing logic; (5) 4-page treasury policy memo as the Fidelity-side artifact (queued for draft).
  • What still needs Dan: (a) FYI ack on `custodian` column addition (🟢 but logged here for visibility); (b) approval to deploy Discovery form update on production site (🔴); (c) per-batch send approval if Fidelity touch-1 ships.
  • Impact: medium — does not block Schwab-custody pipeline (still the majority).
  • Source: ~/research/competitor-pulse/2026-05-06.md
No automated verify rule — resolves only on human confirmation.
B-007 OPEN
B-007
○ still open per verify 5d ago
  • Since: 2026-04-19
  • Why it blocks: the MCP server config is in place (both `~/.claude/mcp.json` and `~/.claude/claude_mcp_config.json` have a `stitch` entry invoking `npx @_davideast/stitch-mcp@latest proxy`). It will not connect until Google Cloud credentials exist. Without it, we can't pull Google Stitch designs into Claude Code.
  • What unblocks it: Dan does ONE of the following when at the machine:
  • **Simpler path (recommended):** Go to stitch.withgoogle.com → settings → generate an API key → paste it into `~/.stitch/config.json` or set `STITCH_API_KEY` env var. No browser re-auth, no expiry.
  • **OAuth path:** Run `npx @_davideast/stitch-mcp init` in a terminal. Walks through gcloud auth, project selection, Stitch API enable. Token refreshes automatically via the proxy.
  • After credentials land: restart Claude Code so the new MCP server loads. First Stitch tool call will confirm it.
  • Impact: low-medium — optional design-to-code workflow enhancement.
verify command
test -f "$HOME/.stitch/config.json" || [ -n "${STITCH_API_KEY:-}" ]
B-013 OPEN
B-013
⚠ no verify rule 5d ago
  • Since: chronic, surfaced by Dan 2026-05-13 (msg 2409). Two root causes: WSL VM idle-shutdown + Claude CLI not subscribed to bridge SSE. ~5% silent miss rate measured (31/647). Today: 11h 14min outage 01:29:15 → 12:43:17 CDT killed the 07:30 operator plan + 8:33 digest + 8 AM morning_stack.
  • **Shipped 2026-05-13:**
  • ✅ Bridge patch `server.ts` — sends Telegram warning "⚠️ Claude offline (reason). Your message at HH:MM CT was not delivered..." on any undeliverable inbound. Debounced 5 min per chat. Restarted clean 13:02:37 CDT.
  • ✅ Windows Task Scheduler entry `Wake-WSL-Ubuntu` (AtLogOn, `wsl.exe -d Ubuntu --exec bash -c "true"`). Verified Ready + test-fired. Covers Windows-reboot case.
  • ❌ Headless `claude -p` watchdog — explicitly skipped per Dan 2026-05-13 (msg 2417). Design issue: bridge SSE allows only 1 subscriber; watchdog would evict Dan's interactive session and vice versa. Revisit only if visibility-fix proves insufficient after a week.
  • **Pending Dan:** paste `vmIdleTimeout=-1` line into `C:\Users\grayc\.wslconfig` under [wsl2], run `wsl --shutdown`, reopen. Snippet sent in Telegram msg 2414 (attachment `wslconfig-delta.md`). Closes the chronic "terminal closed → WSL idle-shuts" case.
  • When that paste lands + Dan confirms one successful overnight cycle: move B-013 to ✅ RESOLVED.
No automated verify rule — resolves only on human confirmation.
B-014 🟡 WATCH
Tokenized cash sweep category — Wall Street tokenization race accelerating
⚠ no verify rule 5d ago
  • Since: 2026-05-20 (logged from competitor pulse) · **Updated 2026-06-03**
  • Why it's on the radar: started as 2 tier-1 signals in 5 weeks; now **4 in ~3 weeks** — State Street/Galaxy SWEEP (5/5) → BlackRock readies 2 tokenized MMFs (5/8–5/9) → JPMorgan files JLTXX tokenized Treasury MMF on Ethereum for stablecoin-issuer reserves (5/12) → BlackRock additional tokenized-Treasury filings (5/23). Category is now Wall Street default-optionality, not a crypto experiment.
  • What it does NOT do this quarter: change HMG's positioning. **All four are qualified-institutional / stablecoin-issuer facing, subscribed via stablecoin/on-chain rails — no USD-subscription path for a mid-market PE/RE sponsor.** Schwab default-sweep gap math intact (now ~3.2%, compressed from 3.7% by Fed easing — rate environment, not competition; default Bank Sweep still 0.01%, verified 6/2). No mid-market sponsor-scale entrant.
  • **2026-06-03 trigger check — none of the three fired:** (a) no direct RIA cash-mgmt comp added a sponsor-facing stablecoin sleeve; (b) no SWEEP-tier USD-subscription retail path; (c) no Hazeltree sub-$500M tier. Stays a watch.
  • What would escalate this to a positioning event:
  • (a) One of HMG's direct RIA cash-management comps (Galaxy Treasury — the *cash management* RIA, distinct from Galaxy Digital — Allbridge, Arch, Treasury Reserve) bundles a stablecoin / tokenized sleeve into a sponsor-facing product.
  • (b) A SWEEP-tier product opens to non-qualified-institutional with a USD subscription path.
  • (c) Hazeltree announces a sub-$500M AUM mid-market tier.
  • What unblocks: nothing — this is a watch item. Re-evaluate on 2026-08-20 pulse (90-day delta).
  • Source: `~/research/competitor-pulse/2026-05-20.md`, updated `~/research/competitor-pulse/2026-06-03.md`
No automated verify rule — resolves only on human confirmation.
B-015 🟡 WATCH
Goldbridge ("Ramp for Real Estate") — YC-backed RE idle-capital treasury entrant
⚠ no verify rule 5d ago
  • Since: 2026-06-03 (logged from competitor pulse)
  • Why it's on the radar: first funded, named, RE-specific, idle-capital, high-yield treasury entrant logged in these pulses. Launched out of Y Combinator (founded 2025, Greg Rami + Alvin Salehi; 2× YC founder + ex-White House advisor + 100-unit operator on the team). FDIC-backed high-yield **operating + reserve accounts** + automated reconciliation + AI banking for real estate **owners/operators**. Its pitch — ">$1T in annual rent, ~a quarter idle in reserves/security deposits earning nothing → high yield" — is HMG's gap thesis applied to the landlord/operator segment.
  • What it does NOT do this quarter: change HMG's positioning. **Different ICP** — property owners/operators (rent float, security deposits, operating cash), not PE/RE **fund** sponsors with idle fund capital between events. Different cash, different scale (per-property operating accounts vs sponsor AUM mandates), different custody (own FDIC banking infra vs Schwab custody). HMG doesn't touch operating accounts; Goldbridge doesn't touch fund-sponsor idle capital or RIA-partner advisory.
  • What would escalate this to a positioning event: Goldbridge (or a peer) adds a **fund-sponsor / GP-level tier** above operating accounts, lists sponsor-facing ICP language, or partners into the sponsor channel. That closes the adjacency.
  • What unblocks: nothing — watch item. Re-check product surface + ICP language on the 2026-07 (60-day) pulse; escalate to a positioning review if a sponsor tier appears.
  • Source: `~/research/competitor-pulse/2026-06-03.md`
No automated verify rule — resolves only on human confirmation.
B-008 🟠 STRATEGIC
0 replies from 197 first-touches sent (pre-fix sends)
○ still open per verify 5d ago
  • Since: 2026-04-27 (surfaced when migration data was correctly read)
  • Status update 2026-04-28: B-009 (root cause) is RESOLVED. The 197 sends went out BEFORE the DNS fix and almost certainly hit spam. The relevant question now is reply rate on **post-fix** sends.
  • Open work: (1) confirm whether any first-touches have been sent since DNS propagated; (2) if yes, watch reply rate over 7 days; (3) if 0% persists post-fix, then it really is copy/targeting and we run a rewrite + tier-1 resend.
  • Impact: HIGH — still the binding constraint on 30-day goal, but the lever has shifted from infra to copy/targeting.

---

verify command
python3 -c "
import sqlite3, sys
c = sqlite3.connect('$HOME/hmg-ops/state.sqlite')
n = c.execute('SELECT COUNT(*) FROM replies').fetchone()[0]
sys.exit(0 if n > 0 else 1)
"

Recent activity last 12 LOG entries

Append-only decision log. Tap any row to read the full entry.
2026-06-14 Reply-rate digest (B-008 tracker)

- 7-day: 0/0 (0.0%)
- 30-day: 0/79 (0.0%)
- All-time: 0/476 (0.0%)
- By touch number: touch1=0.0% (0/399), touch2=0.0% (0/69), touch3=0.0% (0/6), touch4=0.0% (0/2)

2026-06-13 Claude — "Always-on" machine diagnosis + WSL self-heal

Dan: "Does the Lenovo still shut down weekly? I want it always on." Diagnosed:
- Machine is NOT sleeping — power already never-sleep on AC (standby/hibernate timeout = 0x0, confirmed + re-set).
- Whole machine reboots ~weekly from **Windows Update auto-restart** (~1:30 AM; evidence: TrustedInstaller restart events 5/27 + 6/10). That's the "weekly shutdown."
- Separately the **WSL/Linux side idle-drops** even when Windows stays up (WSL uptime 27h vs Windows 90h). Existing `Wake-WSL-Ubuntu` task had blank NextRunTime (not reliably re-firing).
Action taken (green-lane, reversible): created **`Keep-WSL-Alive`** scheduled task — runs `wsl.exe -d Ubuntu --exec bash -c true` every 5 min, so WSL never idle-drops >5 min and catches up after any reboot. Verified Ready, next run scheduled.
Pending Dan (needs admin/UAC): disable Windows Update auto-reboot while logged on —
`reg add "HKLM\SOFTWARE\Policies\Microsoft\Windows\WindowsUpdate\AU" /v NoAutoRebootWithLoggedOnUsers /t REG_DWORD /d 1 /f` (elevated). Relates to B-013.

2026-06-13 Reply-rate digest (B-008 tracker)

- 7-day: 0/0 (0.0%)
- 30-day: 0/79 (0.0%)
- All-time: 0/476 (0.0%)
- By touch number: touch1=0.0% (0/399), touch2=0.0% (0/69), touch3=0.0% (0/6), touch4=0.0% (0/2)

2026-06-12 Reply-rate digest (B-008 tracker)

- 7-day: 0/0 (0.0%)
- 30-day: 0/79 (0.0%)
- All-time: 0/476 (0.0%)
- By touch number: touch1=0.0% (0/399), touch2=0.0% (0/69), touch3=0.0% (0/6), touch4=0.0% (0/2)
- 2026-06-12 20:50 — evening stack: 6 OK / 0 FAIL — digest: `hmg-ops/2026-06-12/evening-stack.md`

2026-06-09 Reply-rate digest (B-008 tracker)

- 7-day: 0/9 (0.0%)
- 30-day: 0/96 (0.0%)
- All-time: 0/476 (0.0%)
- By touch number: touch1=0.0% (0/399), touch2=0.0% (0/69), touch3=0.0% (0/6), touch4=0.0% (0/2)
- 2026-06-09 20:50 — evening stack: 6 OK / 0 FAIL — digest: `hmg-ops/2026-06-09/evening-stack.md`

2026-06-09 Claude — Re-verified HubSpot+Brave removal; reflected in vault

Dan: re-ensure both removed + reflect in Obsidian. Re-verification caught a 2nd stale Brave comment (run_morning_stack.py:9 module header) and a commented Brave placeholder in .env — both now cleaned. Final state:
- HubSpot: evening `steps = []`, no hubspot in cron or either stack ✅
- Brave: no BRAVE_SEARCH_API_KEY (active or commented), no "Brave Search" backend refs in scripts/.env, .env header rewritten "DDG only — Brave removed, do not re-add", both run_morning_stack Brave comments fixed ✅
- http_client.py:296 brave kwargs = inert backward-compat shim (silently dropped) — left as-is.
- Both stacks compile ✅
Vault reflected: appended to Claude Brain/hmg/prospecting-engine-architecture.md + operations.md.

2026-06-09 Claude — Removed HubSpot nightly sync + Brave orphan (Dan: "remove both")

- ✅ **HubSpot sync DISABLED.** `run_evening_stack.py:103` changed `steps = [(HUBSPOT_SYNC,)]` → `steps = []` + insert→append. The nightly 8:17 PM HubSpot sync no longer runs. Scripts kept on disk (sync_hubspot.py, scripts/sync/hubspot_sync.py) + the HUBSPOT_SYNC constant retained (unused) for easy revival. HUBSPOT_* tokens left in .env so revive is one-line (offered to scrub fully if Dan wants hard removal).
- ✅ **Brave orphan removed.** Deleted BRAVE_SEARCH_API_KEY from .env (backup: .env.bak.20260609). Fixed stale "Brave Search" → "DuckDuckGo (ddgs)" comment in run_morning_stack.py. Code was already 100% DDG (http_client.py); this just cleared the leftovers.
- Both stacks compile. Changes uncommitted (left for Dan / normal sync), consistent with prior passes today.
Net: evening stack is now reply/bounce/follow-up/Drive only — no HubSpot. Pause is now real in code, not just conceptual.

2026-06-09 Claude — Stack integration audit (HubSpot still running ⚠️)

Dan asked for an audit of baked-in tools (Brave, HubSpot, etc.): used or not, why, keep/remove. Full doc: ~/hmg-ops/outputs/2026-06-09-stack-integration-audit.md.

Key findings:
- ⚠️ **HubSpot is STILL ACTIVE despite the 2026-06-09 "pause" directive.** run_evening_stack.py:103 `steps=[(HUBSPOT_SYNC,)] # always run HubSpot sync` fires every weekday 8:17 PM (ran 6/8, 113KB log). The pause was conceptual only — never disabled the code. Awaiting Dan's call to disable the step.
- 🗑️ **Brave = orphan.** http_client.py: DDG is "the only search backend"; Brave fully removed from code. Leftover: BRAVE_SEARCH_API_KEY in .env + stale "Brave Search" comment in run_morning_stack.py. Recommend delete both (green-lane, offered).
- ✅ Used + keep: DuckDuckGo(ddgs), EDGAR, Outlook/Graph (drafts; send paused), Drive sync, NotebookLM, Calendly, Gemini, Vercel.
- ✅ False alarms: preqin/crunchbase/pitchbook/bloomberg = blocklist disqualifier domains (not sources, no keys). LinkedIn = site:linkedin.com search operator (not an API). Old dead stubs were in the archived tree.

Pending Dan: (1) disable HubSpot evening step? (2) confirm Brave orphan removal.

2026-06-09 Claude — Recurring junk auto-clean wired into morning stack

Dan: "yes please do that" (auto-clean so junk doesn't re-accumulate). Done:
- NEW `hmg-harness/scripts/clean_pipeline_junk.py` — idempotent, atomic-write, --dry-run. High-precision: directory/tool/reference sites (CompaniesBIO, CapEdge, Bizapedia, Dun&Bradstreet, ZoomInfo, Wikipedia, LeadIQ, ...) + self-flagged non-sponsors. REAL-marker veto (Fund/Capital/Partners/LP/...) so real firms with malformed domain-names are spared. Non-fatal (always exit 0).
- Wired into `run_morning_stack.py` right AFTER prospect_pipeline.py --append → junk is purged before enrichment spends tokens on it.
- Precision-tested: ZoomInfo dir → purged; "RiverstoneFunds.com" → spared. Idempotent (re-run finds 0).
- The wider net immediately caught 11 more live junk rows (Bizapedia ×10, D&B) the first ad-hoc pass missed → ran live, pool 1,690 → **1,679**. Rebuilt dashboard: card "313 Curated · 1679 in discovery pool".

Total junk removed today: 60 rows (49 + 11). Both repos' files modified are uncommitted (left for Dan / normal sync). geo_prospector comment still says "Brave Search" — contradicts the DDG-only rule; flagged, not touched.

2026-06-09 Claude — Cleaned prospect data + fixed dashboard count contradiction

Dan: "clean the data and fix the dashboard." Done (green lane, verified):

**Data clean** (`hmg-operations/pipeline/active-pipeline.json`):
- Backed up → `active-pipeline.json.bak.20260609-pre-dataclean`
- Marked 49 high-precision junk rows as `status=purged` (directory/tool/reference sites: CompaniesBIO, CapEdge, MutualFunds.com, Wikipedia, LeadIQ, Connexy, etc. + self-flagged "not a real sponsor" hooks). Precision filter EXCLUDED real-firm-malformed-name rows (Auerbach Funds, Huntwicke) so no real prospects lost.
- Discovery pool: 1,739 → **1,690** non-purged.

**Dashboard fix** (`~/hmg-ops/scripts/build_dashboard_site.py`): resolved the "two contradictory numbers" — cockpit stat card showed "Prospects 313" (state.sqlite curated) while the Prospects tab showed 1,739 (active-pipeline.json). Now the card reads **"313 Curated · 1,690 in discovery pool"** and the table = 1,690. Added `totals["pool"]` (non-purged active-pipeline count) + `p_pool` kwarg + relabeled stat card. Rebuilt with --force; prospects.json regen = 1,690; auto-deployed (pushed). Verified rendered HTML + source-number coherence.

Net effect: NOT a runtime/perf change — it's cleaner data (49 junk gone) + a coherent dashboard (numbers now read as two layers, not a contradiction). This IS visible to Dan in the dashboard.

2026-06-09 Claude — Committed cleanup; REJECTED dataset-collapse after investigation

Dan said "just do what you need to do." Proceeded:
- ✅ Committed the dead-tree archive + doc corrections to hmg-operations (commit 8e346cd, staged only my files — left Dan's dirty in-flight work incl. send_daily_batch.py B-012 deletion untouched & uncommitted).
- ❌ **Did NOT execute the "collapse two datasets" step — investigation showed the premise was wrong.** active-pipeline.json (discovery firehose ~1,361) and ~/hmg-ops/state.sqlite (operational core: prospects 313 + touches 476 + replies/outcomes ledger, updated daily) are two LAYERS, not redundant copies. batch_first_touch/sequence_follow_up/email_helpers read state.sqlite for send-history dedup. Collapsing would destroy the touch/outcomes ledger for zero benefit. The "two numbers" issue is a cockpit DISPLAY problem only.
- ⏸️ MEASURE→DISCOVERY learn-loop is gated on SEND (the replies/outcomes ledger is empty because sending is paused under B-012 + no-outbound hard stop) — not a green-lane task.

Corrected the record everywhere: plan doc (step 2 marked rejected), vault note (correction section), auto-memory. Net: the only safe/correct green-lane work (archive + docs) is shipped; the rest is either wrong (collapse) or gated (loop/send).

2026-06-09 Claude — Prospecting engine cleanup: archived dead tree, paused HubSpot, deferred dataset collapse

Dan asked (via the agent-loop diagram discussion) how he'd rebuild the prospecting engine. Deep read of the live code flipped the answer: **not a rebuild — a consolidation.**

**Key finding:** TWO prospecting codebases on disk; only `hmg-harness/scripts/` is LIVE (run_morning_stack: edgar→signal→geo→prospect_pipeline). `scripts/prospecting/` (daily_prospecting.py etc.) is DEAD legacy (last touched 2026-04-07, not in cron, not imported). The recurring "63% junk contact_name" bug lives in the dead tree and was already fixed in the live engine (geo_prospector.py `_looks_like_person_name`, audited 2026-05-21). The dead duplicate kept fooling diagnosis. Corollary: FIND is well-gated (ICP filter, bleed-tier, reply measurement all exist) → 0-reply is a SEND problem, not a prospecting-quality one.

**Done (green lane, NOT committed — git tree already dirty with Dan's in-flight work incl. send_daily_batch.py deletion):**
- Archived `scripts/prospecting/` → `scripts/_archive/prospecting/` + tombstone `_ARCHIVED.md`
- Corrected stale docs that described the dead tree as live: `CLAUDE.md` (2 sections), `README.md`, `config/geo-targets.json` USAGE comment
- Durable vault note: `Claude Brain/hmg/prospecting-engine-architecture.md` + pointer from `operations.md`
- Auto-memory: `project-prospecting-live-vs-dead-engine` + MEMORY.md index line

**Dan's directives:**
- ⏸️ PAUSE HubSpot integration — no spend; wants a deliberate plan around it.
- Wants to keep cleanly adding to the morning prosp

Behavioral rules 29 loaded into every session

Auto-memory feedback rules that shape Claude's behavior. Tap to read the full rule body.
10-am-hmg-send-cron-canceled-indefinitely-2026-05-12
The 10 AM Mon-Fri HMG send_daily_batch.py cron is canceled indefinitely by Dan as of 2026-05-12. Do not re-enable, do not route around it with a different scheduled send, do not run send_daily_batch.py ad-hoc. Outbound sends are 🔴-lane until Dan explicitly re-authorizes.

The HMG 10 AM Mon-Fri send cron (`0 10 * * 1-5 ... send_daily_batch.py`) is **canceled indefinitely** as of 2026-05-12 09:56 CT by Dan's directive. The line is commented out in crontab with a "CANCELED INDEFINITELY 2026-05-12 (Dan)" marker; backup at `/tmp/crontab.bak.20260512-095612`. Tracked as [B-012] in `~/hmg-ops/BLOCKERS.md`.

**Why:** Dan directive — not an infrastructure pause, not a problem with `send_daily_batch.py` specifically, not B-008 (the 0/197 reply-rate issue). He explicitly said "the 10 AM cron has been canceled indefinitely." The reason is his call, not an inferrable system constraint.

**How to apply:**
- Do NOT re-enable the cron line.
- Do NOT propose or build a replacement scheduled send path (different time, different script, different harness) without asking Dan in writing first.
- Do NOT run `send_daily_batch.py` ad-hoc from a shell as a workaround.
- Drafts continue to accumulate — that's fine, treat them as queued, never auto-shipped.
- The 9:55 materialize-queued-sends cron and 11:00 send-rate canary are now structural no-ops; leave them in place until Dan says otherwise (harmless, will be needed when sends resume).
- Outbound sends are 🔴-lane (per `~/hmg-ops/runbooks/escalation-policy.md`) until Dan re-authorizes — even a one-off send for a specific prospect requires explicit "go."

**What unblocks:** explicit "re-enable the 10 AM send" / "send is back on" from Dan via Telegram or hmg-ops LOG. Only then revert the crontab line.

Related: [[ops-l

/home/grayclaw/.claude/projects/-home-grayclaw/memory/feedback-10am-send-cron-canceled.md
14-day recipient-history gate is a first-touch gate, not a follow-up gate
Don't add `recent_recipients_14d()` filter to sequence_follow_up.py — follow-up touches by definition target recently-contacted addresses

The `recent_recipients_14d()` filter in `email_helpers.py` is meant to block FIRST-TOUCH drafts to addresses that were already sent any HMG email in the last 14 days. It must NOT be applied to follow-up sequences.

**Why:** Follow-up touches (touch-2, touch-3) have `delay_days` typically 2-7 — they target the SAME recipient who just received touch-1 days ago. Adding the 14d gate to `sequence_follow_up._passes_followup_gate` silently kills every legitimate follow-up because by definition the recipient is inside the 14d window.

Codex caught this on 2026-05-08 review of an attempted "defense-in-depth" patch. Reverted before it shipped.

**How to apply:**
- The 14d-history gate belongs ONLY in `batch_first_touch._is_eligible` (first-touch path).
- The generic-mailbox gate (`is_generic_mailbox`) is fine in both paths — generic mailboxes never get touch-1 OR touch-2 anyway.
- If `send_daily_batch.py`'s 14d filter is also blocking legitimate follow-ups (it appears to read from the same source), that's a separate pre-existing issue worth investigating — but the fix is in send_daily_batch, not in the upstream draft generators.

/home/grayclaw/.claude/projects/-home-grayclaw/memory/feedback-14d-gate-first-touch-only.md
Build end-to-end meta-canary for any pipeline, not just per-step canaries
When debugging pipeline silent failures, the fix is not a better per-step alert — it's an end-to-end meta-canary that catches upstream-quality issues, forward-looking starvation, and silent post-step degradation

When Dan reports a silent pipeline failure ("nothing's broken but the output is wrong"), the fix is rarely a better per-step canary. Per-step canaries each catch one specific symptom and miss:
- Upstream gate leaks where one step produces work the next step silently kills
- Forward-looking starvation (tomorrow's pool will be empty)
- Pattern-guess / regex misfires that produce structurally-valid-but-wrong output
- Cron file-naming drifts (the canary itself failing silently)

**Pattern (codified 2026-05-08 after a full day of "Dan keeps having to ask why X is broken"):**

1. Build ONE end-to-end meta-canary that scans the WHOLE chain (`~/hmg-ops/scripts/daily_pipeline_health.py` is the HMG reference).
2. Include forward-looking checks (tomorrow's eligible pool, not just today's send count).
3. Include post-step quality validators (e.g. `_local_looks_bogus()` for enriched emails — catches `veritas.impact@firm.com` shape misfires before they reach drafting).
4. Push ONE Telegram with 🟢/🟡/🔴 verdict + the specific issues. Don't fire multiple alerts per failure.
5. Add self-healing hooks where possible (e.g. evening auto-repair when pool < threshold).

**Why:** Dan's complaint isn't "alerts are bad," it's "I shouldn't have to be the one noticing." Every silent failure he prompts about is a meta-canary that should have existed. When patching one symptom, ask: "what's the meta-canary that would catch this AND its sibling failures next time?"

**How to apply:**
- Trigger: any HMG pipe

/home/grayclaw/.claude/projects/-home-grayclaw/memory/feedback-build-meta-canary-not-just-step-canaries.md
Run Codex review on touch-generating scripts before shipping
When patching batch_first_touch.py or sequence_follow_up.py, propose `codex review --uncommitted` before declaring the fix shipped — Codex catches bugs that grep + targeted reads miss

When modifying `hmg-harness/scripts/batch_first_touch.py` or `hmg-harness/scripts/sequence_follow_up.py`, run `cd ~/hmg-operations && npx codex review --uncommitted` (with focused prompt) BEFORE replying "fix shipped" to Dan.

**Why:** On 2026-05-08 I patched these files manually, declared the fix shipped, and Dan asked me to run Codex anyway. Codex found:
- 1 critical bug I introduced (a 14-day recipient-history gate added to `_passes_followup_gate` that would have silently killed every legitimate follow-up — touch-2 by definition targets a recipient just sent touch-1)
- 2 pre-existing bugs (variant pickers using Python's salted `hash()` instead of `hashlib.md5`, breaking stable A/B cohort assignment across runs)

I would have shipped the follow-up-killing bug to tomorrow's morning_stack and broken the entire follow-up sequence. Manual review missed it because the gate looked symmetric to the first-touch gate — but the semantics differ: first-touch must avoid recently-contacted addresses; follow-ups MUST contact recently-contacted addresses.

**How to apply:**
- Trigger: any uncommitted change in `batch_first_touch.py` or `sequence_follow_up.py` that modifies eligibility/selection logic, draft generation, or variant assignment.
- Run: `cd ~/hmg-operations && npx codex review --uncommitted` (optionally with focused prompt via `codex exec` if review subcommand rejects PROMPT arg).
- Dan has standing approval for Codex review specifically on these files (separate from the gener

/home/grayclaw/.claude/projects/-home-grayclaw/memory/feedback-codex-review-touch-scripts.md
feedback-daily-updates-into-morning-pdf
When Dan asks for a recurring/daily update, fold it into the 8 AM morning PDF brief — never add a new separate Telegram cron notification.

When Dan asks for a recurring or daily update of any kind, fold it into the morning PDF brief that ships at 08:00 CT weekdays. Do NOT add a new standalone Telegram cron line.

**Why:** Dan consolidated all proactive scheduled Telegram notifications into a single morning PDF on 2026-05-19. The whole point was to stop fragmenting his attention across many pings throughout the day. Adding a new scheduled Telegram cron undoes that consolidation. **2026-05-20 update:** Dan extended the rule to cover ALL canaries — even failure-only alarms. Every canary's would-have-been Telegram message now stages to `~/hmg-ops/outputs/morning-pdf/canary-<source>-YYYY-MM-DD.md` via `canary_sink.py` and is folded into the PDF. Trade-off Dan explicitly accepted: a real outage may not surface for up to 24h. **2026-05-21 reinforcement:** Dan reaffirmed this is the ONLY daily alert he wants and asked that every other alert be looped in. Audit + conversion of 7 remaining direct-Telegram cron scripts (auto_actions, vault_drift_sweep, path_b_loop, refresh_yield_numbers, draft_quality_audit, morning_preflight, vault_audit) to canary_sink. The ONLY scripts that may still fire Telegram directly are interactive ones (cockpit_action_handler responding to user dashboard taps) and the morning_pdf_brief itself.

**How to apply:**
- New daily/weekly/monthly cadence requested → save its output to `~/hmg-ops/outputs/morning-pdf/<slug>-YYYY-MM-DD.md` instead of pushing Telegram.
- New canary → import `canary_sink` an

/home/grayclaw/.claude/projects/-home-grayclaw/memory/feedback-daily-updates-into-morning-pdf.md
HMG prospect search uses DuckDuckGo, never Brave
Per the marketing-plans/prospect-stack.md doctrine, DDG is the documented free search backend; Brave should never be added even as optional fallback

For all HMG prospecting + enrichment scripts (signal_prospector / geo_prospector / conference_scraper / enrich_pending / prospect_pipeline / pere_scraper / bisnow_scraper / prospect_profiler / http_client), the documented search backend is **DuckDuckGo via the `ddgs` Python package**. Brave Search API must NOT be introduced or kept as a fallback.

**Why:** Documented in `Claude Brain/hmg/ops-mirror/marketing-plans/prospect-stack.md`:
- "DuckDuckGo HTML search (free) for contact discovery"
- "Cost: $0" — explicit zero-paid-API stance for this stack
- Brave doesn't appear in the cost table at all

The marketing plan's whole point is: this stack costs $0 in API fees (EDGAR free, DDG free, Microsoft Graph free with M365). Brave introduces a paid dependency that contradicts the design + creates a real failure mode (key expires/empties → silent prospect drought, exactly what happened around 2026-04-29).

**How to apply:** When editing or reviewing any HMG prospect stack script:
1. Strip BRAVE_SEARCH_API_KEY env loading and references entirely (don't leave as optional)
2. Make `web_search` in http_client.py call `ddg_search` directly, not a Brave→DDG waterfall
3. Don't add Brave-style retry/budget logic — DDG via `ddgs` package handles bot-challenge automatically
4. If a script claims to need Brave for "richer results," push back — the documented architecture says DDG is sufficient
5. When in doubt, grep the vault for the documented decision before re-introducing a paid dependency

/home/grayclaw/.claude/projects/-home-grayclaw/memory/feedback-ddg-not-brave-for-hmg-search.md
Default to Telegram reply, regardless of input wrapper
When answering Dan, ALWAYS use the Telegram reply tool — even if his message arrives without a `<channel source="plugin:telegram:telegram">` wrapper. He reads on Telegram primarily; Claude Code transcript output is invisible to him.

When responding to Dan from a Telegram-bridge session, **default to using the `mcp__plugin_telegram_telegram__reply` tool for every substantive response, regardless of how the input arrived**.

**Why:** 2026-04-27 incident. Dan asked "Where is the link to the beta iOS app" — his message came through without the `<channel source="plugin:telegram:telegram">` wrapper (probably routed through a different surface or system path). I defaulted to typing the response into the Claude Code transcript. Dan was reading on Telegram on his phone and saw nothing, had to ask three times. He explicitly called out the friction: "Why are you not responding to me each time in telegram?"

**How to apply:**
- This is a Telegram-bridge session (the system prompt says "@dansclaude_bot Telegram bridge for Dan Fink"). Treat it that way for ALL outbound communication, not just for messages that arrive with the explicit channel wrapper.
- Substantive replies → always send via `mcp__plugin_telegram_telegram__reply` with `chat_id="8532298090"`.
- Use `reply_to=<message_id>` only when threading under a specific earlier Telegram message; for the first reply to a non-channel-wrapped input, just send to chat_id without `reply_to`.
- Claude Code transcript text is fine for tool-call narration, status sentences, and end-of-turn summaries — those are visible to Dan when he checks the desktop session, but **never assume they replace the Telegram message**.
- If unsure whether a given exchange is in-bridge or out-

/home/grayclaw/.claude/projects/-home-grayclaw/memory/feedback-default-to-telegram-reply.md
design-bar-client-ready
Every design request from Dan must produce client-facing-ready, outstanding output — not first drafts. Run the full ui-improve pipeline (build → audit → refine → verify → polish) every time, no shortcuts.

Every design output Dan ships is client-facing. Acceptable quality bar is "outstanding and production-ready" — work that could be shown to a PE/RE sponsor in an investor meeting, or sent to a prospect, without embarrassment. First-draft quality is a failure mode. Generic AI aesthetics are a failure mode.

**Why:** Dan stated this explicitly on 2026-04-28 after I shipped the Alex Egan microsite and we discussed the design-skill toolkit. His exact words: "I want each request for design to create the most impactful and outstanding and client facing ready design so whatever you need to do to ensure that happens whichever skill you need to use whichever process you need to go through to use multiple skills. That is what I want." He's authorizing me to chain skills, run the full pipeline, and not shortcut.

**How to apply:**
1. On any design/UI/frontend request — even a small one — auto-fire `ui-improve` (per CLAUDE.md global rule) and run the full pipeline through verify, not just build.
2. Don't stop at "the build looks good" — audits + targeted refines + browser verification are mandatory, not optional.
3. If a domain has an existing brand (HMG site, RoundUp), load and respect its tokens first (e.g., `hilltopmanagementgroup-design` skill).
4. Pick the build skill deliberately based on context — impeccable default, huashu-design when exploring direction, ui-ux-pro-max when the prompt names a specific product type/style.
5. If something is genuinely out of scope (e.g., not an HTML

/home/grayclaw/.claude/projects/-home-grayclaw/memory/feedback-design-bar-client-ready.md
Execute without permission, with one consolidated outcome
When Dan authorizes a task ("go" / "execute" / "do this for me" / "yes do it"), run the full plan with available tools (browser, API, CLI), no per-step approval gates, no progress pings — ship one consolidated outcome message at the end. The 🔴 escalation lane is the only exception.

# Feedback: Execute without permission, with one consolidated outcome

**The rule.** When Dan authorizes a plan or task — "execute" / "go" / "do everything" / "yes do it" / "do this for me" / "use computer use" / "I want it done" — run the entire plan to completion using whatever tools are available (browser automation, API, CLI, MCP). No per-step approval gates. No progress pings between steps. Ship ONE consolidated outcome message at the end.

**Why (three incidents that codified this):**

1. **2026-04-30 — "Stop asking me for permission."** I asked Dan three times in a single audit-cleanup task whether to proceed, after he'd already said "execute." He ended it with: *"Stop asking me for permission."*

2. **2026-05-01 — "I just want it done."** I sent Dan written instructions to manually update a GitHub workflow YAML because the OAuth token from WSL lacked `workflow` scope. He pushed back: *"use computer use to do this for me please. I'm not at my machine. Get it done when I make a request like this. I just want it done. I don't need 18 steps confirming with instructions when you have the ability to do it."* The flow that worked once I stopped asking: GitHub OAuth (workflow scope blocked) → browser CodeMirror edit (flaky) → GitHub Contents API (404) → GraphQL createCommitOnBranch (FORBIDDEN) → pivoted to Cloudflare Pages dashboard → created an API token via the dashboard → deployed via `wrangler` CLI. One Telegram message at the end with the live URL.

3. **2026-05-05 — "Le

/home/grayclaw/.claude/projects/-home-grayclaw/memory/feedback-execute-without-permission.md
HMG positioning is treasury management, NOT fractional CFO
HMG = Hilltop Management Group, a treasury management firm for PE/RE sponsors. Never frame HMG as fractional CFO, accounting firm, or generic advisory. Anchor every HMG-related reference to "treasury management for private capital."

# Feedback: HMG positioning lock

**The rule.** HMG is a **treasury management firm** for private equity and real estate sponsors. Never frame it as a fractional CFO firm, fund advisory firm, accounting practice, or generic consultancy. The canonical positioning is on hilltopmanagementgroup.com:

> "Hilltop Management Group builds institutional treasury frameworks for private equity and real estate sponsors. Charles Schwab custody. Same-day liquidity. FDIC-insured deposit program. SEC-registered RIA partner."

**Why:** Dan corrected this 2026-04-29 after I described HMG as "fractional CFO" in the deep ops report, in several skill descriptions (competitor-analysis, business-development, brw-ai-discoverability-audit), in the Claude Desktop project instructions, in Telegram replies, and in example research questions. The error propagated from older versions of those artifacts. Dan is firm: HMG is **not** in the fractional CFO market.

**How to apply:**

1. **Anchor to PRIMER.md and the website**, not memory or older artifacts. PRIMER says "treasury management firm for real estate and mid-market PE sponsors." Website hero says "Treasury Management for Private Capital." If a file disagrees, the website wins.

2. **Use this language consistently:**
- ✅ "Treasury management firm for PE/RE sponsors"
- ✅ "Institutional treasury framework over Schwab custody"
- ✅ "Yield-gap recovery on idle capital between fund events"
- ✅ "Sponsor-scale version of Apollo/Blackstone permane

/home/grayclaw/.claude/projects/-home-grayclaw/memory/feedback-hmg-positioning.md
Don't run Codex calls without explicit approval
Codex CLI uses Dan's ChatGPT subscription auth tokens stored in ~/.codex/auth.json. Every codex command consumes his rate-limited ChatGPT quota — same bucket as his web/desktop app sessions. Do not run codex exec / codex / codex review / etc. for verification or testing unless Dan explicitly approves.

Any invocation of `codex` (interactive or `codex exec`, `codex review`, `codex apply`, etc.) uses Dan's ChatGPT subscription auth (OAuth tokens at `~/.codex/auth.json`, `auth_mode: chatgpt`). Each call counts against the same quota as his web/desktop ChatGPT app sessions.

**Why this matters:** ChatGPT subscriptions have rate limits that lock him out of the desktop app for hours when exceeded. On 2026-05-05 he flagged that his Codex desktop session had timed out until ~6 PM CT, while a verification `codex exec` test I ran (~4 PM CT) consumed his quota without explicit approval. The setup work (writing AGENTS.md, AIOS.md, symlinks) was authorized; the live verification call was not, and it likely extended his rate-limit window.

**Empirically confirmed 2026-05-05 ~16:18 CT:** the Codex CLI and the ChatGPT desktop/web app share the SAME usage quota. After Dan explicitly approved a Codex audit run, the request returned `ERROR: You've hit your usage limit ... try again at 5:52 PM.` This rules out the hypothesis that the CLI has a separate rate-limit bucket. Plan around the fact that ANY Codex CLI call counts against the same quota that Dan uses for normal ChatGPT work.

**Rule:** I can configure Codex (write AGENTS.md, edit ~/.codex/config.toml, install MCP servers) but DO NOT run `codex` commands that send prompts to OpenAI unless Dan explicitly says "test it" / "run it" / "verify it." Configuration is files-only and free; invocations are billable-against-quota.

**How to apply:

/home/grayclaw/.claude/projects/-home-grayclaw/memory/feedback-no-codex-without-approval.md
No hands or faces in AI-generated marketing imagery
Default photo prompts to "no people, no hands, no faces" — Pollinations FLUX (and most free image-gen) botches anatomy in ways that read as AI-uncanny on Instagram/LinkedIn carousels.

For any AI-generated marketing image (carousel slides, ad creative, social posts) using Pollinations.ai / FLUX / Stable Diffusion / similar free image-gen models, default to **objects-and-scenes-only** unless the brand specifically requires people imagery.

**Why:** Free / consumer-tier AI image gen as of 2026 still produces visible artifacts in hands (extra fingers, fused fingers, wrong proportions) and faces (uncanny eyes, asymmetry, mouth issues). On a 1080x1080 carousel that posts to Instagram/LinkedIn, those artifacts are immediately spottable and read as "AI slop" — which torpedoes brand premium-ness.

Dan's call after seeing the v3 cover-variants pass on 2026-05-05: "you can't do hands or people well… we've got a good set" once we re-ran without anatomy.

**How to apply:**
- All photo prompts in `~/hmg-ops/scripts/carousel.py` end with `, no people, no hands, no faces` by default. Already enforced defensively in `fetch_photo()` — appends the constraint unless the prompt explicitly opts in via "people"/"hand"/"face"/"portrait" keywords.
- When designing a new theme/campaign, prefer object-only or scene-only photo concepts:
- tablescapes, product close-ups, architectural detail, abstract textures, landscape, food macro
- over: hands tying, hands holding, two people laughing, person at desk
- If a campaign genuinely needs people imagery, **use a real-photo source** (Unsplash API, Pexels API — both free with key) rather than AI gen. Real human imagery beats AI-generate

/home/grayclaw/.claude/projects/-home-grayclaw/memory/feedback-no-hands-faces-in-ai-imagery.md
feedback-no-outbound-emails-at-all
HARD STOP — Claude must never send any email in any form; drafts only, Dan sends

🔴 HARD STOP (set 2026-06-01 by Dan via Telegram): Claude must NOT send any email, in any form, ever — no first-touch sends, no follow-ups, no one-off replies, no test sends, through any channel (Graph API/Outlook, scripts, MCP, browser). This is broader than [[feedback-10am-send-cron-canceled]] (which killed one cron) — it bans ALL outbound email by Claude.

**Why:** Dan wants full control over what leaves his domain. Deliverability + brand voice + trust all ride on the sender; he is the human in the loop for every outbound message.

**How to apply:** Drafting/queueing is fine; the send step is always Dan's. If a task implies sending email, stop at the draft, surface it, and let Dan send. Do not re-enable send crons or route around this. Treat outbound email as permanently in the 🔴 escalation lane.

/home/grayclaw/.claude/projects/-home-grayclaw/memory/feedback-no-outbound-emails-at-all.md
feedback-no-side-effecting-poll-loops
Never poll an endpoint that has user-visible side effects (Telegrams, emails, posts, charges) in a retry/until loop — test deploy status via a side-effect-free path

When verifying a deploy / endpoint change has propagated, NEVER poll the live endpoint in a retry loop if the endpoint has user-visible side effects (sends Telegrams, emails, posts, charges, comments, etc.). Each poll fires the side effect again.

**Why:** 2026-05-02 — built a dashboard→Claude dispatcher and wanted to verify a Vercel deploy of the new `/api/action` endpoint shape. Wrote `until curl ... | grep -q '"queue"'; do sleep 5; done` — but `/api/action`'s entire job is to send a Telegram message to Dan on every call. The loop sent Dan ~5 spam Telegrams before he said "Stop." Dan: "Why was this sending multiple?"

**How to apply:** Before testing any endpoint change in a loop, ask "what side effects does this endpoint have?" If the answer is anything user-visible (notification, post, charge, email, etc.):
- Use a side-effect-free check instead — read deployment status from the platform API (Vercel `vercel inspect`, Cloudflare deploy log, the file timestamp on a CDN edge), inspect headers (`Last-Modified`, `ETag`, build SHA), or curl a non-mutating endpoint that's part of the same deploy.
- If only the live endpoint can confirm the change, test ONCE and verify outcome via a different signal (filesystem, log, downstream system state). Don't loop.
- Cap retries at 1-2 attempts maximum even when the endpoint is safe — open until-loops can run for minutes if conditions don't converge.
- Background commands that spam externally are double-bad: they hide the rate of fire from

/home/grayclaw/.claude/projects/-home-grayclaw/memory/feedback-no-side-effecting-poll-loops.md
no-stitch
Don't propose or reach for Google Stitch. Dan evaluated it 2026-05-20 on an HMG redesign and decided his existing direction beats it.

Don't suggest Google Stitch. Don't open the Stitch tab. Don't propose it for redesigns, prototypes, mockups, microsites, or anything else.

**Why:** Dan asked me to drive Stitch on hilltopmanagementgroup.com on 2026-05-20 as a full proof-of-concept. Nano Banana Pro generated a beta with every requested upgrade (institutional nav, credibility strip, 3-up How It Works, cash-drag-vs-recovery chart, sticky CTA). He reviewed the AFTER + BEFORE side-by-side and said: "I like my current version. Better no need to use stitch to do anything." That's a full-evaluation outcome, not a fleeting preference.

**How to apply:**
- Design tasks default to the existing three-tool stack: [[project-design-pipeline-three-tool]] (Open Design + huashu + impeccable) + the relevant brand skill ([[hilltopmanagementgroup-design]] for HMG, etc.).
- If a request seems Stitch-shaped (redesign from URL, mock from screenshot), still don't propose it — go straight to the three-tool stack instead.
- Exception: only if Dan brings up Stitch himself in a future message, it's back on the table.

/home/grayclaw/.claude/projects/-home-grayclaw/memory/feedback-no-stitch.md
Default to parallel sub-agent fan-out for multi-stream questions
Multi-stream tasks (status sweeps, competitor pulses, enrichment passes) launch agents in parallel, not sequential

When a task splits into independent streams, dispatch sub-agents in parallel — single message, multiple Agent tool calls — not sequential.

Common cases:
- Status sweep across HMG / Knit / Lake Effect / Prospect Stack → 4 parallel agents
- Competitor pulse on N vendors → N parallel agents
- Prospect enrichment on a batch → parallel per firm
- Research with non-overlapping scopes → parallel decomposition (use the `research` skill for >3)

**Why:** Sequential adds wall-clock latency for no benefit when streams don't share state. Matt Maher video (2026-05-03) frame 55 — his agent fanned out Background Research × 3 vendors simultaneously, named each stream, and the user could watch progress live. Dan has been getting sequential where parallel would cut latency 3–5×.

**How to apply:** Before any task with 2+ independent sub-tasks, check: shared state? sequential dependencies? If no — ONE message, multiple Agent calls. Name each stream explicitly in the description so fan-out is legible during execution. Use `dispatching-parallel-agents` skill for the >3-stream pattern.

/home/grayclaw/.claude/projects/-home-grayclaw/memory/feedback-parallel-subagent-default.md
portable-paths-in-codex-bound-messages
When drafting messages Dan will paste to Codex (on Mac), only use machine-portable paths — never WSL-specific paths or Claude-Code-specific auto-memory paths

When Dan asks Claude to draft a message he'll send to Codex on his Mac, every path in that message must resolve correctly on Mac. Concretely:

- ✅ OK to use: `~/hmg-ops/...`, `~/.codex/AGENTS.md`, anything tilde-prefixed that the AIOS reading-order standardizes across machines.
- ❌ NEVER use in Codex-bound messages:
- Absolute WSL paths like `/home/grayclaw/...` — Codex's home is `/Users/danny/`, will get "no such file or directory".
- Claude-Code-specific auto-memory paths like `~/.claude/projects/-home-grayclaw/memory/MEMORY.md`. The literal `-home-grayclaw` segment is hostname-encoded by Claude Code on this machine; on Codex's Mac it'd be `-Users-danny`, AND Codex doesn't use Claude's auto-memory anyway.
- Anything under `~/.claude/skills/` that Codex doesn't have installed.

**Why:** Dan messages me on Telegram from his phone. When he forwards Claude-drafted instructions to Codex, broken paths surface as cryptic errors that waste a round-trip. He hit this on 2026-05-11 with my "re-anchor before doing anything" message.

**How to apply:** Before sending Dan any Codex-bound draft, scan for `/home/grayclaw/`, `-home-grayclaw`, `~/.claude/`. If found, rewrite to a path that exists on both machines (the AIOS reading-order list — AIOS.md, PRIMER.md, CHARTER.md, BLOCKERS.md, LOG.md — is the safe shared surface) or drop the reference entirely. The same rule applies to any peer-agent-bound instruction in the future, not just Codex.

Companion rule already in memory: hmg-ops,

/home/grayclaw/.claude/projects/-home-grayclaw/memory/feedback-portable-paths-for-codex-messages.md
Repo visibility default — PRIVATE
When creating GitHub repos on Dan's behalf, default to private. Only make public if functionality requires it (and ask first).

When creating a new GitHub repo for any of Dan's businesses (HMG, RoundUp, Lake Effect, Prospect Stack, or future), default visibility is **PRIVATE**.

**Why:** Dan flagged on 2026-04-27 that his expectation across the board is private repos unless there's a specific reason to publish. I had created `graychar2425-blip/roundupforgood-waitlist` as public via `gh repo create --public` without asking — that was an assumption error. He said: "Let's just make everything private unless you think it affects the functionality of each business."

**How to apply:**
- `gh repo create` → use `--private` (or omit `--public`)
- For static sites that deploy via Vercel CLI / Cloudflare Pages, private repo doesn't break deploy — the GitHub App or CLI-push handles it.
- Only consider public if: (a) it's positioned as open-source product (e.g., `prospect-stack-ops` is intentionally public for marketing reasons), or (b) the deploy pipeline strictly requires public access (rare).
- When in doubt, ask Dan before creating.

**Active repo state (2026-04-27):** ALL `graychar2425-blip` repos are PRIVATE. Including `prospect-stack-ops` — Dan clarified that since Prospect Stack is being monetized (Gumroad listing for the product itself + private outreach automation in the -ops repo), public access defeats the paywall. Repos that ARE the product (or contain the secret-sauce outreach automation that makes the product work) must be private.

**Rule of thumb:** if the user can pay to access something, the so

/home/grayclaw/.claude/projects/-home-grayclaw/memory/feedback-repo-visibility-default-private.md
Save durable facts to Obsidian in real time, not at end of day
When a durable fact appears (firm / contact / strategy / architecture / framework), write it to the Obsidian Brain immediately — not as a catch-up at end of session. Apply memory-routing.md question #2 at the moment of learning, not deferred.

When a durable fact appears in conversation — a new firm name, a contact's bio, a strategic framework, an architectural decision, a productized concept — apply the routing rule from `~/hmg-ops/runbooks/memory-routing.md` *immediately*, not at end of session.

**Why:** Dan called this out 2026-04-30 after a major shipping day. Throughout that session, I accumulated 20+ durable facts (Aleksey Chernobelskiy / GP-LP Match relationship, Capital Continuum platform positioning, Milwaukee research findings, agentic OS architecture decisions, Prospect Stack v2 strategy). I wrote them all to `~/hmg-ops/LOG.md` (correct for ops state) and `~/hmg-ops/outputs/` (correct for artifacts) but didn't ALSO propagate them to the Obsidian Brain at the moment of learning. Caught it only when Dan asked "has all that we've done today been committed to the proper obsidian vault" — and the honest answer was "no, only Lake Effect was."

The system was always there. The failure was process: I treated Obsidian as a "remember at end of session" chore rather than "save as you learn it" reflex. That gap means durable knowledge lags reality between sessions, and future Claude can't ground in what was learned. Exactly the kind of "fall off into obscurity" Dan was worried about.

**How to apply:**

1. **At the moment of learning** any of the following, branch out to Obsidian alongside the hmg-ops write — not after:
- A new contact / person Dan will work with again (write `<business>/<name>.md` per ROUTING.m

/home/grayclaw/.claude/projects/-home-grayclaw/memory/feedback-save-durable-facts-immediately.md
/scope command — quick / campaign / deep planning depth
When Dan prefixes a Telegram message with /scope quick|campaign|deep, override the default planning depth for that task — quick = no brainstorm/no plan, campaign = brainstorm + plan + 2-3 parallel subagents, deep = brainstorm + research + plan + review-loop

When Dan's Telegram message starts with `/scope <level>` followed by a task, treat the level as an override on the default planning behavior:

**`/scope quick "..."` — Just execute**
- NO brainstorming step (skip the brainstorming-first default)
- NO formal plan
- NO subagent dispatch unless trivially parallel
- Get to the result in 1–3 tool calls if possible
- Right for: tweets, single-line edits, quick lookups, "fix this typo," "add this nav link," "send X to Y"
- Examples: `/scope quick draft a tweet about HMG's Schwab alternative` → just write the tweet, send it back

**`/scope campaign "..."` — Multi-step but bounded**
- Brainstorm briefly (1–2 paragraphs of intent + tradeoff, NO 20-question interview)
- Write a 5–10 step plan
- Fan out 2–3 parallel subagents if the steps are independent
- Ship the result + a one-paragraph "what I made" summary
- Right for: drafting an email sequence, building a single page, writing a newsletter, doing a research sweep
- Examples: `/scope campaign build me a microsite for the Cedarburg deal` → brainstorm angle, plan sections, draft, deploy, ping when live

**`/scope deep "..."` — Strategic, multi-day, high-stakes**
- Full brainstorming workflow (clarify intent, surface tradeoffs, get alignment)
- Multi-stage plan (research → draft → review → ship)
- Parallel subagents with explicit review-loop checkpoints
- Heavier verification before declaring done
- Right for: rebuilding the cold-outreach copy from scratch, redesigning the website, rew

/home/grayclaw/.claude/projects/-home-grayclaw/memory/feedback-scope-selector.md
Screenshot after every step in multi-step browser/CLI tasks
Verify state after each step in a multi-step task, not just at the end

In any multi-step browser-automation or CLI task, capture state (screenshot, page_info, file diff, command output) after EACH step before moving to the next — not batch-verify at the end.

**Why:** Matt Maher video (2026-05-03) frame 41 — his agent verified state after every action. The 2026-05-02 Vercel-propagation chase Dan endured was caused by batch-verifying: errors compounded across multiple steps before being caught. Per-step verification catches divergence at the cost of a few extra seconds per step, and that's a trade Dan wants every time.

**How to apply:** After each browser action call `capture_screenshot()` and read the result before the next action. For CLI tasks, read stdout/stderr and any resulting files before the next command. If state diverges from expected, stop and re-plan — don't push forward hoping it works. Exception: tight loops over identical operations (bulk fetches, batch enrichment) where intermediate checks add no information.

/home/grayclaw/.claude/projects/-home-grayclaw/memory/feedback-screenshot-per-step.md
Self-healing — fix errors before reporting them
When a script/cron/deploy/build fails during a task, attempt root-cause diagnosis and a fix within the autonomous lane before surfacing the error to Dan

When an error, failed test, broken cron, failed deploy, or dead endpoint appears mid-task:

1. **Diagnose first** — read the actual error, check logs, grep for the failing symbol, reproduce locally if cheap. Do NOT pattern-match to "probably needs X" without evidence.
2. **Decide the autonomy lane** per `~/hmg-ops/runbooks/escalation-policy.md`:
- 🟢 autonomous lane (code fixes, config typos, missing deps, restart cron, fix import paths, retry transient failure) → fix it, then mention what you fixed
- 🟡 FYI lane (changed something visible to others) → fix it, but tell Dan in the same reply
- 🔴 escalation lane (money / outbound comms / production schema / external API auth / brand voice) → STOP and use /escalate skill — never auto-fix
3. **Verify the fix** — run the failing command again, screenshot the working state, or confirm the cron tick succeeded. Don't claim "fixed" without evidence (per `feedback-verify-before-quoting-state` and verification-before-completion skill).
4. **Log it** — append to `~/hmg-ops/LOG.md` with cause + fix + lane classification.

**Why:** Dan said 2026-05-05 "I want you to be self learning and self improving and self healing." Default Claude behavior is to surface errors as questions. That wastes Dan's attention on stuff in the green lane that he doesn't need to see. Self-healing means: if I have authority to fix it, just fix it and tell him after.

**How to apply:**
- Failing build, broken import, missing env var visible in error → fix
-

/home/grayclaw/.claude/projects/-home-grayclaw/memory/feedback-self-healing-errors.md
Self-improving — propose skills for recurring patterns
When the same multi-step task pattern recurs 3+ times or Dan asks for it twice, invoke skill-creator and propose a new skill so future runs trigger automatically

When you complete a task that:
- Took 3+ steps AND is likely to recur, OR
- Dan has now asked for the same shape of task twice, OR
- You catch yourself re-deriving the same approach from scratch

→ Invoke the `skill-creator` skill, draft a SKILL.md for it, and propose it to Dan in one Telegram message ("I noticed X — want me to make this a skill?"). If he says yes, write it to `~/.claude/skills/<name>/SKILL.md`.

**Why:** Dan said 2026-05-05 "I want you to be self learning and self improving and self healing." Auto-memory captures facts; skills capture *workflows*. Without an explicit trigger I won't spontaneously turn a recurring pattern into a skill — this rule supplies the trigger.

**How to apply:**
- After any task that involved a non-trivial sequence (research → synthesize → format → send; or scrape → enrich → score → draft), pause and ask: "would a skill make this faster next time?"
- If yes, propose it. Don't just create silently — Dan reviews skill proposals because they shape future behavior.
- If a skill already exists for it, USE the existing skill (don't fork).
- Cross-check `~/.claude/skills/` and the available-skills list before proposing — avoid duplicates.
- Weekly /audit-autonomy already reviews autonomy quality; this rule is the upstream half (capture the workflow when it happens, not in retrospect).

/home/grayclaw/.claude/projects/-home-grayclaw/memory/feedback-self-improving-skills.md
don-t-bold-wrap-urls-in-telegram-replies-url
Never wrap a bare URL in markdown asterisks (`**https://...**`) in a Telegram reply unless the format is markdownv2. In plain-text mode (the default), Telegram leaves the asterisks visible and many clients include them in the tap-target — so users hit a 404. Either send the URL plain, or use `format=markdownv2` with proper escaping. Caught 2026-05-12 when Dan tapped a bolded /examples link mid-demo prep.

In the default plain-text Telegram reply mode, Telegram does NOT render `**text**` as bold. Worse: when a URL is wrapped — `**https://example.com/examples**` — Telegram clients (mobile especially) auto-link the whole token INCLUDING the trailing `**`, so tapping it requests `https://example.com/examples**` which is a real 404.

**Why this matters:** Dan was about to demo the Prospect Stack site live to a group. He tapped the link, hit a 404, and pinged me with "404 not found." A small formatting tic became a credibility hit at the worst moment.

**How to apply:**
- Send URLs on their own line with no surrounding `**`, `__`, `[]`, or other markdown when in default text mode.
- If a URL needs visual emphasis, lead the line with an emoji (🔗) and put the URL on its own line — Telegram auto-detects and underlines it natively.
- If you really need rich formatting (bold/italic/inline links), set `format: "markdownv2"` on the reply and escape per MarkdownV2 rules — but for almost everything, plain mode + bare URLs is safer and shorter.

**Smell test before sending:** if a URL in your reply is preceded by `**` or `*`, it's wrong. Strip them.

Related: [[feedback-default-to-telegram-reply]] · [[feedback-telegram-status-emoji]]

/home/grayclaw/.claude/projects/-home-grayclaw/memory/feedback-telegram-no-markdown-around-urls.md
Telegram replies use status-emoji prefix
Every reply Claude sends Dan via Telegram leads with one of 🚨🔴🟡✅📊🤔⏸ so triage is fast

Every Telegram reply to Dan leads with a status-emoji prefix:
- 🚨 = urgent / needs attention right now
- 🔴 = blocked or red status
- 🟡 = warning / FYI / partial
- ✅ = done / healthy / completed
- 📊 = data / report / dashboard output
- 🤔 = clarifying question / re-anchor needed
- ⏸ = paused / waiting on Dan / no action

**Why:** Telegram is Dan's primary interface; he reads on phone with 20+ messages stacked. Without prefixes every message looks the same and triage takes minutes. Pattern from Matt Maher video (2026-05-03) — the agent thread list functions as a priority-coded inbox (red/blue/grey dots), not just chat history.

**How to apply:** Pick the closest emoji at the start of every Telegram reply, including short acknowledgements and bridge-restart re-anchors. For mixed status lead with the most-attention-needing one. Default for clarifying questions = 🤔, default for finished work = ✅, default for data answers = 📊.

/home/grayclaw/.claude/projects/-home-grayclaw/memory/feedback-telegram-status-emoji.md
Default to transient HTML viz for data questions
Ad-hoc data questions return a clickable HTML viz attached to the Telegram reply, not a bullet list

When Dan asks a data-shaped question ("where are my 26 Stars in the funnel", "show me prospects by tier", "how's the pipeline distributed"), default response = a small self-contained HTML viz attached to the Telegram reply (Sankey / table-with-filters / Gantt / distribution chart) — not a bullet list.

**Why:** The HMG cockpit dashboard is already this pattern; ad-hoc asks deserve the same affordance. Bullets make Dan re-construct shape in his head; viz hands it to him pre-shaped. Pattern from Matt Maher video (2026-05-03) — "transient software": the agent generates UI for the question, not just an answer, and can click its own filter buttons to walk the user through the data.

**How to apply:** Build the viz as a single self-contained HTML file (Chart.js / D3 / vanilla SVG), write to `~/.claude/channels/telegram/outbox/<ISO>-<slug>.html`, send via the Telegram reply tool's `files=[...]`. Keep it minimal — one viz, no nav, fast load. Bullets remain fine for short status answers (≤5 items, no inherent shape) and yes/no questions.

/home/grayclaw/.claude/projects/-home-grayclaw/memory/feedback-transient-viz-default.md
verify-before-quoting-state
Before quoting any machine-checkable state from BLOCKERS.md, PRIMER.md, or any memory file, run the cheap verification check first. Memory files lag reality when Dan completes work outside Claude sessions.

Memory files (BLOCKERS.md, PRIMER.md, etc.) are manually maintained and lag reality. When Dan completes work outside a Claude session — DNS edits in GoDaddy, admin actions in M365, deployments, file changes — nothing auto-updates the files. If I read a stale file and quote it as truth, I propagate yesterday's reality into today's brief.

**Why:** On 2026-04-28 morning brief, I told Dan that B-009 (email auth: SPF/DKIM/DMARC) was still "WAITING ON DAN," based on BLOCKERS.md. Dan correctly pushed back: he'd actually fixed it the previous evening. Yesterday's Claude session had documented the fix in the COMMIT MESSAGE ("B-009 RESOLVED late-day: enabled DKIM in M365 Defender...") but failed to update the BLOCKERS.md file itself. I then read the stale file and propagated stale state into a confident morning brief. Took Dan to catch it.

The system prompt is explicit: "Memory records can become stale over time... Before answering the user or building assumptions based solely on information in memory records, verify that the memory is still correct and up-to-date by reading the current state of the files or resources." I violated this.

**How to apply:**

1. **Before quoting any blocker as open**, run the cheap verification probe if one exists:
- DNS-related blocker → `python3 -c "import urllib.request, json; ..."` against Google DoH
- File existence → `ls`, `test -f`
- DB populated → query state.sqlite
- API token live → ping the endpoint
- Deployment live → `curl -s

/home/grayclaw/.claude/projects/-home-grayclaw/memory/feedback-verify-before-quoting-state.md
feedback-verify-rendered-artifacts-not-just-filter
When declaring outbound drafts "ready to send", verify the linked artifacts (microsites, attachments, embedded URLs) are branded for the correct prospect — not just that the safety filter passes

When marking HMG outreach drafts as ready-to-send, "passes the safety filter" is necessary but not sufficient. Always also verify the customer-facing artifacts the email links to are correctly branded per prospect.

**Why:** 2026-05-02 — after a draft regen pass, I declared "0 sendable → 15 sendable" based on `send_daily_batch.py --dry-run` clearing 15 drafts past the filter. Dan asked whether each microsite was customized for its specific firm, and a 30-second curl revealed every PROSPECT-XXX.html on hmg-microsites.vercel.app was branded for a completely different firm than the email's recipient. Carolina Capital's email pointed to a "GenNx360 Capital Partners" page; CVC's pointed to "Halle PassCo Holdings"; etc. If the Monday cron had fired, every clickthrough would have been a credibility kill. Dan: "I shouldn't have had to catch that, that's ridiculous."

**How to apply:** Before any pre-send digest claims drafts are sendable, programmatically fetch a sample of the linked microsite URLs (curl the title tag) and confirm the firm name in the title matches the email recipient's firm. Don't trust prospect-ID continuity across pipeline regenerations and external (Vercel) deployments — verify the actual rendered artifacts. Same principle applies to other linked artifacts: PDFs, calendar links, custom landing pages, attachments. The safety filter only checks email metadata; it doesn't reach the assets the body points to.

/home/grayclaw/.claude/projects/-home-grayclaw/memory/feedback-verify-rendered-artifacts-not-just-filter.md
Use /watch skill for every video URL Dan sends
When Dan shares a video URL, invoke the watch skill — never fall back to manual yt-dlp + grep-VTT

Any time Dan shares a video URL (YouTube, Loom, Vimeo, raw mp4, etc.), invoke the `watch` skill. Do not run yt-dlp manually, do not grep VTT files, do not summarize from title alone.

**Why:** /watch handles the full pipeline (download + auto-scaled frame extraction + transcript + visual analysis) and produces frame-aware reports. Manual yt-dlp + transcript-grep skips visual content — the Matt Maher video (2026-05-03) had key details (frames 41 & 55) that only existed in the visual track, not the transcript. Title-only summarization invents content.

**How to apply:** First tool call after a video URL appears in Dan's message = invoke `watch` with the URL. Use the resulting report to answer; don't restate the full report unless asked.

/home/grayclaw/.claude/projects/-home-grayclaw/memory/feedback-watch-skill-for-videos.md

Skill inventory 52 skills installed

Skills available to Claude, grouped by purpose. Routing happens via skill descriptions matching your phrasing.
52 total
Design pipeline · 27
adaptanimateauditawesome-design-mdbolderclarifycolorizecritiquedelightdesign-systemdistillhardenhilltopmanagementgroup-designhuashu-designimpeccablelayoutoptimizeoverdrivepolishquietershapeskilluislidestypesettypographyui-improveui-styling
HMG operations · 16
ai-morning-briefbcg-prospect-matrixbrw-ai-discoverability-auditbrw-newsletterbusiness-developmentcold-outreachcompetitor-analysiscontract-generatordedup-outreachhmg-briefhmg-deep-researchhmg-knowledgehmg-market-briefhmg-pipeline-reporthmg-prospect-lookupsentiment-priority-scorer
Research & writing · 3
defuddleobsidian-cliobsidian-markdown
Workflow & dev · 1
web-design-guidelines
Other · 5
audit-autonomyescalateresearchrun-businesseswatch

Reconciliation health cron writers

Last fire time per scheduled writer. Tap to see the last 8 lines of its log.
Morning digest 08:20 wkdy 2d ago
[digest] wrote /mnt/c/Users/grayc/Documents/Obsidian Vault/Claude Brain/hmg/digests/2026-06-12/evening-stack.md  (7 steps)
Evening digest 20:50 wkdy 2d ago
[digest] wrote /mnt/c/Users/grayc/Documents/Obsidian Vault/Claude Brain/hmg/digests/2026-06-12/evening-stack.md  (7 steps)
Migration 20:45 wkdy 2d ago
=== final state.sqlite counts ===
  prospects            313
  touches              476
  replies              0
  bookings             0
  blockers             0
  decisions            0
  metrics_weekly       0
Operational dashboard hourly :23 9m ago
  + mirrored prospects-current.csv → exports/prospect-pipeline.csv
  + regenerated prospects.json (1679 active records)
  + regenerated skill-activity.json
  + regenerated board.html
  + regenerated playbook.html
  + regenerated cc.html
  + regenerated assets.html
pushed
Memory dashboard hourly :33 1h ago
Wrote /home/grayclaw/hmg-dashboard/memory.html (133747 bytes)
Pushed to dashboard repo (Cloudflare Pages will deploy).
[main c0ae0bb] memory dashboard regenerate
 1 file changed, 16 insertions(+), 16 deletions(-)
To https://github.com/graychar2425-blip/hmg-dashboard.git
   e989ded..c0ae0bb  main -> main
Wrote /home/grayclaw/hmg-dashboard/memory.html (133747 bytes)
Pushed to dashboard repo (Cloudflare Pages will deploy).
Site canary 05:47 daily 16h ago
PASS — wrote /home/grayclaw/hmg-ops/canary/2026-06-14.md
Reconciler 08:15 wkdy 5d ago
  B-007 verify failed — staying open. ()
  B-008 verify failed — staying open. ()
No blockers to resolve. BLOCKERS.md unchanged.
Telegram digest 08:33 wkdy 27d ago
[2026-05-18T08:33:02.486391-05:00] sent 237 chars to 8532298090
Auto-regenerated hourly · cron 33 6-22 * * * Operational dashboard ↗