Skip to content

feat: v3 architecture + cross-platform hardening#29

Merged
benslockedin merged 8 commits intomainfrom
v3-projection-redesign
Apr 10, 2026
Merged

feat: v3 architecture + cross-platform hardening#29
benslockedin merged 8 commits intomainfrom
v3-projection-redesign

Conversation

@benslockedin
Copy link
Copy Markdown
Contributor

Summary

  • Full v3 architecture rewrite — rules, skills, templates, hooks, and scripts updated for v3 structure (flat _kernel/, no bundles/ container, JSON tasks via tasks.py, now.json computed by project.py)
  • Cross-platform hardening.gitattributes for LF line endings (fixes Windows), portable stdin handling, UTF-8 encoding safety, getpass.getuser() for Windows USER env var, os.replace() over os.rename()
  • Org rebrandstackwalnutsalivecontext across install commands, README, CHANGELOG
  • PII cleanup — removed real references, generic examples throughout
  • Stale v2 references removed_kernel/_generated/, bundles/ prefix, tasks.md, now.md all updated to v3 equivalents
  • Metadata corrected — hook count (14→13), rule count (5→6), hooks.json version (v2→v3)

What changed (22 commits)

v3 architecture (15 commits)

  • All 6 rules rewritten for v3
  • 9 skills updated for v3 paths and tasks.py integration
  • Templates updated (flat kernel, JSON tasks, 3-file load sequence)
  • Hooks updated (project.py trigger on log.md, flat kernel paths, backward compat)
  • generate-index.py reads v3 flat now.json
  • Subagent brief updated to v3
  • 03_Inputs/ → 03_Inbox/
  • Plugin owns runtime (no stale world copies)

Cross-platform fixes (7 commits)

  • .gitattributes — forces LF for .sh/.py/.md/.yaml/.json (CRITICAL for Windows)
  • cat /dev/stdincat (Git Bash portability)
  • generate-graph.pyencoding='utf-8' on all open(), narrowed bare except:, guarded json.load()
  • tasks.pyos.replace() over os.rename(), getpass.getuser() for Windows, removed unused imports
  • generate-index.py — removed unused import
  • Setup.md — purged all stale v2 scaffolding paths
  • Reconciled stash checkpoint contradiction in rules

Test plan

  • Fresh install on macOS: claude plugin install alive@alivecontext
  • Fresh install on Windows (WSL): clone, verify hooks fire
  • Fresh install on Windows (Git Bash): clone, verify .gitattributes prevents CRLF
  • Existing v2 world: run /alive:system-upgrade, verify migration
  • Create new walnut: verify _kernel/ is flat (no _generated/, no bundles/)
  • Run tasks.py on Windows: verify getpass.getuser() works
  • Run generate-graph.py with malformed _index.json: verify graceful error
  • Verify generate-index.py reads v3 now.json correctly

🤖 Generated with Claude Code

@patrickSupernormal
Copy link
Copy Markdown
Collaborator

alivecontext/alive — Open PR Merge Safety Review

Reviewer: Patrick Brosnan (patrickSupernormal, non-collaborator — advisory only; comments are not approving reviews that satisfy branch protection)
Date: 2026-04-09
Scope: 7 open PRs surveyed; 5 deep-reviewed; 2 matrix-only (#32 self, #34 draft)
Methodology: structured survey → conflict matrix → sequential per-PR deep reviews → this synthesis. Generated via flow-next epic fn-8-vly (7 tasks, all done).


TL;DR — Recommended Merge Order

  1. PR fix: post-write hook debounce break outside loop #35 (post-write hook breakexit 0) — GREEN, merge first. Smallest possible unit (1 line), zero overlap, CI green, currently producing stderr noise on every repeated save. No rebase, no fixes, no dependencies. Land it.
  2. PR fix: tasks.py crashes on malformed tasks.json in archive dirs #28 (tasks.py archive crash) — YELLOW, author response needed. The advertised ~40-line fix is correct, but the diff hides a 260-line undisclosed v2→v3 migration subsystem with real bugs (duplicate task IDs, destructive os.remove fallback, over-broad wildcard, read-mutates-filesystem surprise, zero tests). Ask Ben to either split the PR or fix the bugs + disclose scope + add unit tests. The underlying archive-skip crash IS real and actively breaking save operations on supernormal-systems, so this is urgent once addressed.
  3. PR feat: Hermes Agent integration — memory provider, skills, crons #33 (Hermes Agent integration) — YELLOW, 6 mechanical fixes needed. Architecturally clean isolation (pure +2961/-0 under a new hermes/ top-level directory, zero file overlap with anything), but 6 real bugs need a follow-up commit before merge. Middle of the queue: after confidence-building fixes ship, before the hard architectural work.
  4. PR feat: v3 architecture + cross-platform hardening #29 (v3 architecture + cross-platform) — GREEN code, DIRTY merge state. Every hunk is correct on close read; no bugs found. But branch is ahead_by 8, behind_by 26 against main and needs a 15-30 minute rebase (10 conflicting files, all mechanical — no architectural decisions needed). Most urgent content: setup.md currently instructs the agent to read template files that don't exist on main, breaking every fresh walnut creation via /alive:world setup. Merge in slot 4 to unlock fix: rebuild context graph for v3 #31.
  5. PR fix: rebuild context graph for v3 #31 (context graph rebuild for v3) — YELLOW, R-1 silent regression. Stacked on feat: v3 architecture + cross-platform hardening #29's branch; cannot merge until feat: v3 architecture + cross-platform hardening #29 lands. The visual redesign is a strict improvement, but the data pipeline rewrite silently removes top-level recent_sessions: and unsigned_with_stash: from the world index — which plugins/alive/skills/world/SKILL.md explicitly reads ("DO NOT read .alive/_squirrels/*.yaml files — recent session data is IN the index under recent_sessions:"). This will break the /alive:world dashboard after merge. Fix R-1 before merging.

Independent-from-#29 bucket (can merge any order, any time after their own fixes): #33, #35.
Depends-on-#29 bucket (must merge after #29): #31.
Overlap-with-#29 bucket (can merge before, but creates rebase work): #28, #32.


The Big Picture


Conflict Matrix

Per-PR file count

PR Files Author Role
#28 1 Ben tasks.py archive crash fix
#29 15 Ben v3 architecture + cross-platform
#31 2 Ben context graph rebuild for v3 (stacked)
#32 45 Patrick P2P v3 (self-review, matrix only)
#33 27 Ben Hermes Agent integration
#34 1 Ben myalive.ai teaser landing (draft, matrix only)
#35 1 Ben post-write hook debounce break

Total unique files across all 7 PRs: 84

Pairwise overlap

Sorted by overlap count descending. Pairs with zero overlap are omitted (18 of 21 pairs have no overlap).

Pair Count Files
#29 × #32 5 plugins/alive/hooks/hooks.json, plugins/alive/skills/load-context/SKILL.md, plugins/alive/skills/save/SKILL.md, plugins/alive/skills/search-world/SKILL.md, plugins/alive/skills/world/setup.md
#29 × #31 2 plugins/alive/scripts/generate-graph.py, plugins/alive/scripts/generate-index.py
#28 × #29 1 plugins/alive/scripts/tasks.py

Total overlapping pairs: 3 out of 21 possible pairs.

Key observations:

File matrix (compact — only rows with 2+ touches shown)

File #28 #29 #31 #32 #33 #34 #35
plugins/alive/hooks/hooks.json
plugins/alive/scripts/generate-graph.py
plugins/alive/scripts/generate-index.py
plugins/alive/scripts/tasks.py
plugins/alive/skills/load-context/SKILL.md
plugins/alive/skills/save/SKILL.md
plugins/alive/skills/search-world/SKILL.md
plugins/alive/skills/world/setup.md

The remaining 76 files are each touched by exactly one PR and pose no conflict risk.

PR #29 divergence details

Branch state against main: ahead_by: 8, behind_by: 26, merge base a44f146 (2026-04-03T10:58Z). In the ~1 hour after #29 branched, Ben merged 26 commits to main including the full v3.0.0 release cycle, the People revert (eac03d3 — "People stays in 02_Life/people/"), the domain-folder rule, the inbox triage agent, Windows compat (shasum/symlink fallbacks, Unicode stdin UTF-8), the search cascade, the statusline .alive/ detection, and 12 README/hero GIF/trailer tweaks. Roughly half substantive, half cosmetic — both kinds touch files #29 also touches.

10 files require merge conflict resolution during rebase: CHANGELOG.md, README.md, plugins/alive/hooks/scripts/alive-common.sh, plugins/alive/rules/squirrels.md, plugins/alive/skills/load-context/SKILL.md, plugins/alive/skills/save/SKILL.md, plugins/alive/skills/search-world/SKILL.md, plugins/alive/skills/world/setup.md, plugins/alive/statusline/alive-statusline.sh, plugins/alive/templates/walnut/key.md.


Per-PR Verdicts

PR #35 — post-write hook debounce break

URL: #35
Size: 1 file, +1/-1 (plugins/alive/hooks/scripts/alive-post-write.sh)
Merge state: CLEAN, CI green

Standalone safety: GREEN

The bug on main is real and user-visible. alive-post-write.sh:53 on main has [ "$AGE" -lt 300 ] && break sitting inside a case */log.md) block, inside an if [ -n "$WALNUT_PATH" ], AFTER the while ... done loop on lines 37-43 has already closed. There is no enclosing loop at that nesting level. In bash, break with no loop prints bash: break: only meaningful in a 'for', 'while', or 'until' loop to stderr and returns a non-zero status for that statement — but bash does NOT exit the script; it continues to the next line.

That means the debounce on main is doubly broken: (1) the hook emits stderr on every repeated save, which Claude Code can surface as a hook failure; (2) execution falls through to touch "$MARKER" and re-invokes project.py anyway, so the 5-minute debounce never actually skips anything.

The fix replaces break with exit 0, which cleanly terminates the hook. This is the correct primitive — no enclosing loop, no function scope, so break/continue/return are all wrong. exit 0 is the only right answer. It also mirrors the established pattern for the second debounce block at line 80 which already uses [ "$AGE" -lt 300 ] && exit 0.

The activity counter for statusline (lines 14-22) runs BEFORE the first case block, so it is unaffected by the early exit — activity tracking still happens on every write, including debounced ones.

Inter-PR compatibility: None. Zero file overlap with any other open PR. No semantic or behavioural interactions with #29's refactor or #33's Hermes subsystem — this hook's debounce logic is local.

Merge order role: FIRST / EARLY. Merge immediately, ahead of everything else in the batch. 1-line fix, CI green, CLEAN merge state, fixes stderr noise on every repeated save. Merging first also removes any chance that Ben's rebase of #29 accidentally reintroduces the broken break.

Recommendation: Merge as-is. Merge this first of the batch. No rebase needed. No author response needed. No dependencies.


PR #28 — tasks.py archive crash fix

URL: #28
Size: 1 file, +304/-21 (plugins/alive/scripts/tasks.py)
Merge state: CLEAN, CI green

Standalone safety: YELLOW

The two fixes advertised in the PR body are both correct in isolation:

  • The skip_dirs expansion in _all_task_files (lines 310-315) correctly adds _archive, _references, 01_Archive, raw.
  • The strict=False mode added to _read_json (lines 11-38) is a reasonable way to let bulk readers skip malformed files without aborting, while single-target commands (add, done, edit) continue to hard-fail.

These two changes alone would be a ~40-line GREEN PR. But the body undersells the diff. Actual change is +304/-21, not ~40 lines. The undisclosed ~260 lines add a full v2→v3 auto-migration subsystem (_migrate_tasks_md, _upgrade_v2_json, _ensure_tasks_json, _parse_task_line, _SECTION_PRIORITY). None of it is mentioned in the PR summary. Scope creep that obscures review.

4 concrete bugs in the hidden subsystem:

  1. Read operations mutate the filesystem. _all_task_files now calls _ensure_tasks_json (line 341) AND _migrate_tasks_md (line 347) for every file found. _all_task_files is called by _find_task, _collect_all_tasks, and the list/summary commands — all nominally read-only. A tasks.py list that silently renames tasks.mdtasks.md.v2-backup, writes a new tasks.json, and writes a new completed.json violates least-astonishment.

  2. Destructive fallback in _migrate_tasks_md (lines 193-198): if tasks.md.v2-backup already exists, the fallback is os.remove(md_path) — the original tasks.md is deleted with no backup. Silent data loss on a read operation. Can hit on a second invocation, on a manually-restored tasks.md, or on any branch where a prior run created a .v2-backup.

  3. Latent duplicate-ID bug in _upgrade_v2_json (lines 244-264): counter starts at 1 and increments uniformly whether the task is v2-upgraded or v3-kept-as-is. For a mixed v2/v3 file, a v2 task can land on t001 when a v3 t001 already exists. Example: [v2_task, v3_task_with_id_t001][{id: t001, ...}, {id: t001, ...}]. Two tasks with id t001 in one file, no error raised, silent corruption. Fix: seed counter from _next_id(tasks) or track used IDs in a set.

  4. Wildcard skip is broader than documented (lines 319-324): adds and "archive" not in d.lower() to the dirs[:] filter. Any directory whose name contains "archive" is silently skipped. Catches _archive/01_Archive (intended) but ALSO catches user-named walnuts like website-archive-rebuild, content-archive-review, email-archive-export. The PR body only lists the four explicit dir names; the wildcard is undocumented and could drop legitimate task files from live walnuts. Fix: drop the wildcard clause.

Plus: renumbering breaks external references (migrated tasks get fresh IDs starting from counter=1 — any log.md/bundle/doc reference to a v2 task by id now points somewhere else or nowhere); priority flattening for completed tasks (line 113 returns "priority": priority if not is_done else "todo" regardless of source section); zero unit tests for +260 lines of parsing/migration/writing code.

Inter-PR compatibility: Conflicts with #29 (textual only, not semantic). Both touch tasks.py, but hunks are in disjoint regions:

Neither PR touches the lines the other modifies. git may report a conflict purely because #28's large insertion shifts #29's target line numbers, but 3-way merge resolves mechanically. Whichever lands first, the other rebases in under a minute.

Compatible with: #31, #32, #33, #34, #35.

Merge order role: Middle (after #35, before #29/#31/#33), and gated on author response about the migration subsystem.

Recommendation: Author response needed before merge — DO NOT merge as-is. Ask Ben to choose:

  1. Split the PR. Land the archive-skip + strict=False changes as a minimal PR (~40 lines). Put the v2→v3 migration subsystem in a separate PR with its own test coverage, body, and bugs fixed. Cleanest path — two concerns are orthogonal, and the crash fix is urgent.
  2. Keep as one PR but fix + disclose + test. Update body to describe the migration subsystem. Fix the duplicate-ID bug (seed counter from _next_id). Fix the destructive os.remove fallback (raise an error or write to .v2-backup.{timestamp}). Drop the "archive" wildcard. Add at least three unit tests (mixed v2/v3 file, pure v2 tasks.md migration, mixed archive-dir + live-dir walnut). Document the read-path mutation in body and module docstring.

PR #33 — Hermes Agent integration

URL: #33
Size: 27 files, +2961/-0 (pure additions, zero deletions — all under new hermes/ top-level directory)
Merge state: CLEAN, CI green

Standalone safety: YELLOW

Architecturally clean isolation. Everything lives under hermes/ — a new top-level directory never touched by existing plugin code. Zero deletions, zero modifications of existing files, no hook registration inside plugins/alive/hooks/hooks.json, no changes to plugin.json. On merge, the worst-case impact is "a new directory exists" — no runtime interaction with the rest of the plugin.

Stdlib-only Python. Memory provider imports only json, logging, os, re, threading, uuid, datetime, pathlib, typing + the Hermes framework. No PyYAML, no requests, no cryptography, no network calls. plugin.yaml declares pip_dependencies: [].

No security surface: no external API keys, no network calls, no subprocess execution, no file I/O outside ALIVE_WORLD_ROOT. Path handling uses Path.relative_to(world_root) with a ValueError guard (line 2642) which correctly prevents escaping the world.

But 6 real bugs need a follow-up commit:

  1. hermes/install.sh:2025-2032 — quoted heredoc silently disables shell expansion. cat > ... << 'WORLDKEY' uses a single-quoted delimiter, so line 2028 created: $(date +%Y-%m-%d) lands in the world key as the literal string $(date +%Y-%m-%d). Every Path B onboarding run produces a malformed .alive/key.md. Fix: change << 'WORLDKEY' to << WORLDKEY (unquoted) or compute date into a variable first.

  2. hermes/hermes-skills/alive-search/SKILL.md:34 — typo: missing underscore in glob. First glob is "$ALIVE_WORLD_ROOT"/*/kernel/log.md (missing the _). Top-level walnuts (the common case, e.g. 04_Ventures/stellarforge/_kernel/log.md) are silently excluded from log search. Fix: */kernel/log.md*/_kernel/log.md.

  3. hermes/memory-provider/__init__.py:2838-2871started and ended timestamps both equal session-end-time. on_session_end computes a single now_iso and writes it to both fields. initialize() never captures the start time. Every squirrel YAML entry shows zero-duration sessions, breaking duration-aware tooling. Fix: capture self._started_at in initialize(), use it for started: in on_session_end.

  4. hermes/memory-provider/__init__.py:2682-2694on_turn_start walks the entire world on every turn. for key_file in self._world_root.rglob("_kernel/key.md"): iterates every walnut on every user message, then only uses the result to emit a logger.debug(...) call — no state change. At 138 walnuts (per PR body), that's 138 filesystem stat calls per turn for a debug log line. Contradicts the provider's headline "smart prefetch saves tokens" value prop. Fix: cache the list at initialize() time, or remove the loop entirely since it doesn't influence state.

  5. hermes/setup-crons.sh:3050-3104 — silent error hiding on every hermes cron create. 2>/dev/null && echo "[+]" || echo "[!] failed" discards the stderr that would tell the operator WHY the create failed (hermes not installed, flag unknown, schedule invalid), and the || echo rescue prevents set -euo pipefail from aborting. Operator sees 8 "[!] failed" lines with no diagnostic. Fix: write stderr to a log file or capture into a variable and echo on failure.

  6. hermes/setup-crons.sh:3090 vs hermes/cron-templates/alive-mine/SKILL.md:1 — skill name mismatch. Cron registers --skill alive-mine-cron, but the folder is alive-mine/ and the SKILL.md frontmatter declares name: alive-mine-cron. Whether this works depends on Hermes' resolver. Fix: pick one name, apply consistently.

Plus minor issues (not blockers): walnut-name match uses substring instead of word boundary (daily matches "write a daily summary"); on_memory_write stashes every write unconditionally as insight_candidate (over-capture); hand-rolled YAML parser won't handle block scalars or lists; YAML writes are non-atomic (no tmp-rename); no tests for 838 lines of provider code.

Inter-PR compatibility: None. Every file lives under hermes/ (100% prefix match). Cross-referenced against #28, #29, #31, #32, #34, #35 — zero file overlap, zero semantic overlap, zero dependency. Fully orthogonal. The memory provider reads _kernel/key.md, _kernel/log.md, _kernel/insights.md, and _kernel/now.json — all stable paths on main.

Merge order role: Middle (position 3-4). Fully isolated, can technically merge at any position, but size (27 files, +2961 LOC) means it deserves fresh reviewer attention — not late when fatigued by conflict resolution.

Recommendation: Author response needed before merge — but a lightweight one. Ask Ben to land a follow-up commit fixing the 6 bugs above. Tests are absent but I would NOT block merge on adding them, given the isolation — Ben can ship the provider, get real Hermes users on it, and add tests once the API stabilises. The architectural direction is correct; the follow-up is mechanical.


PR #29 — v3 architecture + cross-platform hardening

URL: #29
Size: 15 files, +54/-36
Merge state: DIRTY / CONFLICTING (ahead_by: 8, behind_by: 26)

Standalone safety: GREEN (but the PR cannot merge as-is because of the textual conflict against main — the code itself is correct, the merge state is dirty).

Is this PR still relevant? Yes. Verified every file on current main HEAD (a143365). 14 of 15 file hunks are still bringing value. Only the first hunk of generate-graph.py (encoding='utf-8' on the _index.json open) is now a no-op because a separate commit on main already added it. The most urgent content: setup.md on main currently instructs the agent to read template files (now.json, tasks.md) that don't exist in templates/walnut/ after v3.0.0 removed them. Every fresh walnut created via /alive:world setup on current main will fail at that step. #29's setup.md block fixes this — it is the most important file in the PR.

Subsystem overview: 15-file cleanup PR touching six concerns:

  • .gitattributes (new) — cross-platform LF line endings
  • MetadataCHANGELOG.md (5→6 rules), README.md (14→13 hooks), hooks.json description (v2→v3)
  • Windows compatalive-common.sh Windows python3 Store-stub fallback (py -3 shim) + cat /dev/stdincat portability fix (also in alive-statusline.sh)
  • Python hardeninggenerate-graph.py (UTF-8 encoding, narrowed bare except, guarded json.load), generate-index.py (drops dead pathlib import), tasks.py (getpass.getuser() in place of os.environ.get("USER"), drops dead pathlib import)
  • Skill scrub — five files scrubbed of stale v2 path references (bundles/{name}/{name}/, _kernel/_generated/_kernel/, now.mdnow.json, tasks.mdtasks.json)
  • Rule reconciliationsquirrels.md removes the contradictory "shadow-write every 5 items" language and asserts save IS the checkpoint consistently

No bugs found. Every individual change is correct on a close read. No TODO/FIXME/debug. No security surface. No regression surface. The Windows python3 fallback is the right pattern (validate execution with python3 -c "", fall back to py -3, shim a bash function so call sites stay unchanged). The getpass.getuser() swap is the canonical Python cross-platform idiom.

Inter-PR compatibility:

Conflicts with #32 (Patrick's — textual, 5 files, low friction). All 5 conflicts are same-intent-different-wording. Resolution ~5 minutes per file, ~15 minutes total:

Conflicts with #31 (dependency, not textual). #31 is stacked on #29's HEAD (de8d602) via baseRefName: v3-projection-redesign. #31's base SHA = #29's head SHA exactly. Zero textual conflict between them. The dependency is one-directional: #31 cannot merge until #29 lands because its base branch only exists on PR #29's side.

Conflicts with #28 (textual, 1 file, low friction). Both touch tasks.py, but hunks are in disjoint regions (verified by reading both diffs). Neither PR touches the lines the other modifies. git may report a 3-way conflict because #28's ~260-line insertion shifts #29's line numbers, but resolution is mechanical. Under 1 minute.

Compatible with #33 (Hermes) and #35 (post-write debounce) and #34 (landing page draft). Zero file overlap. The Hermes memory provider reads _kernel/* paths which are stable on main — #29 doesn't change the path layout.

Merge order role: Late, but BEFORE #31. Specifically: slot 4 of 5 (after #35 GREEN, after #28 once author response resolves its issues, after #33 once follow-up fixes land). #31 must come immediately after #29 in slot 5.

Rebase guidance for Ben (for resolving the 26-commit divergence):

  1. git rebase main on v3-projection-redesign. Expected conflict files (10): CHANGELOG.md, README.md, alive-common.sh, squirrels.md, load-context/SKILL.md, save/SKILL.md, search-world/SKILL.md, setup.md, alive-statusline.sh, walnut/key.md.
  2. Key conflict-resolution guidance:
  3. Run the Windows (Git Bash) smoke test from the PR's own test plan. This is the only test that genuinely requires a human — the py -3 shim cannot be validated from a Mac.
  4. Force-push. CI re-runs. Merge state should flip from DIRTY to CLEAN.

Gap in PR body: The body claims "22 commits" but the actual branch has 8 (ahead_by: 8). Ben is likely counting commits from a superseded branch. Harmless.

Recommendation: Merge after rebase — no code changes required. Expected effort: 15-30 minutes of mechanical conflict resolution + 1 Windows smoke test. Do NOT close this PR as obsolete — 14 of 15 hunks still bring real value, and setup.md in particular is the most important cleanup.


PR #31 — context graph rebuild for v3

URL: #31
Size: 2 files, +984/-1022 (net -38 LOC, heavy churn — effectively a rewrite)
Merge state: CLEAN against its base branch v3-projection-redesign, NOT main

Standalone safety: YELLOW

Base SHA de8d602 verified identical to PR #29 HEAD SHA. #31 has fully absorbed #29's tip changes on generate-graph.py and generate-index.py; there is zero textual conflict between the two on these files.

What the PR actually does:

  1. generate-index.py rewritten to be v3-aware: reads _kernel/ as walnut parent dir, parses now.json as JSON, detects bundles via {walnut}/{bundle}/context.manifest.yaml scanning, strips [[wikilinks]], infers parent-child relationships from filesystem hierarchy, builds bidirectional people↔walnut links. Adds per-walnut enrichment: task_counts, bundle_summary, blockers, session_count, last_session, children.
  2. generate-graph.py is a full visual rewrite from v3 "circle-packing + expandable capsules + pinned world-root + inputs buffer" to v4 "force-directed + domain-gravity-wells + Obsidian-style neighborhood highlighting + semantic zoom + click-to-pin-detail-panel". Explicitly cites Obsidian graph view as inspiration.
  3. Health signals computed client-side — rhythm_days map matches plugins/alive/rules/world.md exactly (daily=1, weekly=7, biweekly=14, monthly=30; active/quiet/waiting thresholds identical).
  4. Legacy v2 fallback retained (_capsules/ scanning and _core/_kernel/_generated/now.json path candidate) — good, matches v3 backward compat posture.

R-1. CRITICAL: top-level recent_sessions: and unsigned_with_stash: removed from _index.yaml and _index.json.

The OLD code computed a world-level recent_sessions list by walking .alive/_squirrels/*.yaml (mtime-sorted, top 10) plus an unsigned_with_stash counter for sessions with saves: 0 AND non-empty stash:. The NEW code deletes both and replaces them with a PER-WALNUT session_count and last_session derived from that walnut's own now.json.recent_sessions. That is a useful enrichment BUT it lives on individual walnut entries, not at the top level.

Downstream breakage verified via GitHub code search on alivecontext/alive@main: plugins/alive/skills/world/SKILL.md on main (SHA e6e14b9) lines 21, 67, 198 explicitly document: "Unsigned squirrels with stash: already in the index as unsigned_with_stash:" and "recent sessions are in the index under recent_sessions: and unsigned stash count is in unsigned_with_stash:. DO NOT read .alive/_squirrels/.yaml files"*.

After #31 merges, those two fields will be absent. The world dashboard skill will either silently render without the session pulse / attention section, or crash trying to read a missing field, depending on how defensive its Bash/jq queries are. /alive:world is the most-invoked skill in the system.

Fix path: Re-add both computations to generate-index.py before the YAML/JSON write. The old code (removed in this PR) is the correct implementation and can be restored verbatim — the removal looks accidental (the PR body doesn't mention removing these fields, and world/SKILL.md was never updated). Alternatively, push the data into per-walnut now.json and update world/SKILL.md to aggregate on demand — but that requires updating world/SKILL.md in the same PR.

R-2. MAJOR: graph loses the "world root" centrepiece node and the "inputs" buffer node.

The OLD graph read .alive/key.md name field, built a central "world root" node labelled with the human's world name, and connected it to top-level walnuts. It also added an "inputs" node sized 14 showing the 03_Inbox count. The NEW graph has NEITHER. Intentional design change (matches the PR body's force-directed reasoning) but not explicitly called out. The user-visible effect: opening /alive:my-context-graph after this PR shows a graph without the named world root node that used to be the visual anchor and without the inputs indicator.

Fix: restore both as pinned-centre "special: true" nodes, OR update user-facing docs + /alive:world + /alive:my-context-graph skills to stop referencing them.

R-3 to R-7 (yellow / minor):

  • Stats header drops inputs and sessions; display label "bundles" but underlying JSON key still capsules — cosmetic mismatch
  • Dead 3-nested-loop code in bidirectional-links section (innermost branch is literally pass) — delete
  • Exception handler in now.json reader breaks out of the candidate loop on JSONDecodeError, stopping fall-through to v2 path — restore now_json_loaded flag pattern
  • recent_sessions semantic confusion (old = world-level list, new = per-walnut list) — rename one or document
  • Module docstring downgraded from "v3" back to "v2" in generate-index.py — cosmetic regression, looks like a merge accident

R-8 through R-15 (all OK or notes, not bugs): The JSON clean function is intentionally lossier (handled defensively downstream). No TODO/FIXME. No security surface. Force-directed layout is mathematically sound. Health-ring computation matches world.md. PR body's 6-item test plan is unchecked. Edge cases (empty world, single walnut, no frontmatter, deep nesting) all handled. Bundle counting semantic change (scan walnut root for context.manifest.yaml vs _capsules/) is effectively zero-risk in practice.

Inter-PR compatibility:

Conflicts with #29 (DEPENDENCY, not textual). Stacked on #29's HEAD. Zero textual conflict — #31 has already eaten #29's tip. Cannot merge before #29 because its baseRefName: v3-projection-redesign only exists on the PR #29 side. Retarget-to-main is impractical because #31 is explicitly a v3 rebuild of the two files; applying it on main without #29's base is a mess.

Interaction with #29's rebase: Ben's rebase of #29 touches CHANGELOG.md, README.md, alive-common.sh, squirrels.md, setup.md, statusline.sh, walnut/key.md, plus one-line SKILL.md edits and tasks.py edits — NONE of which substantively change generate-graph.py or generate-index.py. So #31's two-file patch will continue to apply cleanly after #29's rebase.

Compatible with #28, #32, #33, #34, #35. Zero file overlap (scripts/ vs. all the other PR file sets).

Merge order role: Position 5 of 5 (last), immediately after #29. Stacked dependency is absolute. Once #29 lands, GitHub auto-retargets #31 to main and it flips mergeable. Because #31's two files are disjoint from every other PR, its merge order relative to #28/#33/#35 is flexible — only the "after #29" constraint is hard.

Recommendation: Merge after #29 — BUT fix R-1 first. Priority order:

  1. Restore top-level recent_sessions: and unsigned_with_stash: in generate-index.py. The removed code in the diff is the correct implementation — restore it verbatim and keep the new per-walnut enrichment. Both can coexist. ~80 lines of code restoration + 20 lines of output emission.
  2. Restore the "world root" + "inputs" centrepiece nodes in the new force-directed layout OR update docs + skills to no longer reference them.
  3. Delete dead nested-loop code, fix the now.json reader fall-through, restore v3 docstring, rename stats key to bundles. All ~5-line mechanical fixes.
  4. Run the 6-item test plan, specifically items 1-4 (generate-index runs, generate-graph runs, open the HTML verify clusters, v2 backward compat).
  5. Merge in position 5, immediately after feat: v3 architecture + cross-platform hardening #29.

Before merging, run python3 .alive/scripts/generate-index.py locally and grep -c 'recent_sessions\|unsigned_with_stash' .alive/_index.yaml — if the count is zero, R-1 is unfixed. If non-zero, the fix landed.


PR #32 — P2P v3 (Patrick's, matrix-only)

URL: #32
Size: 45 files, +20792/-22

Self-review conflict of interest — no substantive verdict. This PR is Patrick's own work (superseding #27), so any merge-safety verdict from Patrick would be self-serving. No verdict rendered.

Inter-PR impact: 5-file overlap with #29 on plugins/alive/hooks/hooks.json, plugins/alive/skills/load-context/SKILL.md, plugins/alive/skills/save/SKILL.md, plugins/alive/skills/search-world/SKILL.md, plugins/alive/skills/world/setup.md. Per the detailed inter-PR analysis in the PR #29 verdict above, all 5 overlaps are textual same-intent-different-wording. Resolution time during #32's post-#29 rebase: ~15 minutes total (~5 min per hunk, 4 hunks require manual picking, 1 auto-merges). Note for Patrick's own rebase of #32: main's eac03d3 reverted the People walnut path back to 02_Life/people/, but #32's setup.md still has the OLD People/ path because #32 branched earlier. #32 will need to pick up the People revert during its rebase.

CI status: UNSTABLE is a first-time-contributor gate, NOT a test failure.

  • Head SHA 1e54465 on branch fn-7-7cw
  • gh pr checks 32: "no checks reported on the 'fn-7-7cw' branch"
  • /commits/1e54465/check-runs: empty array
  • /commits/1e54465/check-suites: conclusion action_required, latest_check_runs_count: 0, pull_requests: []
  • Combined status: {state: pending, total_count: 0, statuses: []}

Diagnosis: Patrick is a first-time contributor to alivecontext/alive (verified: role_name: null). GitHub's default policy for public repos is that workflows on PRs from first-time contributors require a collaborator to click "Approve and run" before check runs dispatch. That's exactly what happened — the check-suite exists but GitHub never dispatched any runs. This is not a code-quality signal. No tests have run. No tests have failed. UNSTABLE here means "unknown", not "broken".

Action for Ben: Go to PR #32's Checks tab and click "Approve and run workflows". This dispatches the check runs. Results then become a real signal. Until approval, UNSTABLE should be treated as "unknown".

Action for Patrick: Cannot fix this from the outside. Adding commits won't help — every new commit from a non-collaborator re-triggers the same gate.


PR #34 — myalive.ai teaser landing (draft, matrix-only)

URL: #34
Size: 1 file, +557/-0 (sites/myalive.ai/index.html)
Status: DRAFT

Draft — out of scope for merge review. Not ready for merge.

Inter-PR impact: Zero overlap with any other PR. Single file under its own subtree sites/myalive.ai/. Can merge at any position in any order once Ben takes it out of draft.


Blockers (must resolve before each PR can merge)

None of the 5 deep-reviewed PRs are RED standalone (no PR has a blocking safety issue against current main). But several need pre-merge fixes:

  • PR fix: tasks.py crashes on malformed tasks.json in archive dirs #28 — Author response required. Hidden 260-line v2→v3 migration subsystem with 4 bugs (duplicate task IDs, destructive os.remove, over-broad wildcard, read-mutates-filesystem). Either split the PR or fix the bugs + disclose scope + add unit tests.
  • PR feat: Hermes Agent integration — memory provider, skills, crons #33 — 6 specific follow-up fixes needed (install.sh quoted heredoc, alive-search glob typo, on_session_end timestamps, on_turn_start filesystem walk, setup-crons.sh stderr handling, alive-mine naming consistency). All mechanical.
  • PR feat: v3 architecture + cross-platform hardening #29 — Rebase against current main (15-30 min mechanical, 10 conflict files, no architectural decisions). Plus a Windows (Git Bash) smoke test to validate the py -3 shim.
  • PR fix: rebuild context graph for v3 #31 — R-1 silent regression (drops recent_sessions: and unsigned_with_stash: from index, breaks /alive:world dashboard). Must restore before merge. Plus the "world root" / "inputs" nodes either restored or documented-away. Plus minor cleanup (R-3 through R-7).

PR #35 has no blockers. Merge it first.


Notes for Ben


Where this report was posted

Posting URLs appended here after the report landed on GitHub. See bottom of document.


Generated via flow-next worker chain (Claude Code) as epic fn-8-vly. 🐿️

supernormalsystems and others added 8 commits April 11, 2026 00:18
Prevents CRLF breakage on Windows for shell scripts, Python, Markdown,
YAML, and JSON files.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
/dev/stdin is not available on all platforms. Plain cat reads stdin
by default and is more portable across Linux, macOS, and Windows (WSL).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Remove stale v2 references: _kernel/_generated/ subdirectory, bundles/
container directory, tasks.md. Update to v3 flat kernel (now.json at
_kernel/ level), tasks.json + completed.json, and correct people walnut
paths (02_Life/people/).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- generate-graph.py: add encoding='utf-8' to open() calls, narrow bare
  except to (ValueError, TypeError, KeyError), add try/except around
  json.load() for graceful error handling
- tasks.py: replace os.environ.get("USER") with getpass.getuser() for
  Windows compatibility, remove unused pathlib import
- generate-index.py: remove unused pathlib import

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- load-context: bundles/{name}/ -> {name}/ (v3 flat bundles)
- save: remove bundles/*/tasks.md reference, use tasks.py
- search-world: bundles/research/ -> research/ in example
- walnut key.md template: now.md -> now.json

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- hooks.json: v2 -> v3 in description, 14 -> 13 hooks (archive enforcer
  was removed in v3)
- README.md: 14 -> 13 hooks in install line and runtime diagram
- CHANGELOG.md: 5 -> 6 rules rewritten (matches actual count)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The Stash Checkpoint section correctly states save IS the checkpoint with
no automatic mid-session writes. The Stash Discipline section and
instinct 11 contradicted this with shadow-write timers. Reconciled both
to match: save is the checkpoint, transcript JSONL is crash recovery.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Windows ships a python3 stub (AppInstallerPythonRedirector.exe) that passes
`command -v` but fails to execute (exit code 49). This caused all Python-
dependent hooks to silently fail: no now.json generation, no index updates,
empty squirrel entries.

Fix: validate python3 actually runs (`python3 -c ""`), then try the Windows
py launcher (`py -3`), shimming it as a python3 function so all existing
callsites work without changes. Falls through to node if neither works.

Fixes: Windows hooks silently broken due to python3 Store stub

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@benslockedin benslockedin force-pushed the v3-projection-redesign branch from de8d602 to a76b6d5 Compare April 10, 2026 14:21
@benslockedin benslockedin merged commit 835c406 into main Apr 10, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants