Technical Museum
All Hardware Maps ML & AI Music Social Tools Writing Apps & Games
Deciduous
Decision graph CLI for tracing how software decisions evolve
Rust SQLite HTML/JS
Deciduous Archaeology Demo
Demonstrations of decision archaeology on React and stacked git workflows
Rust React Git
Phish Explorer
Jam analytics dashboard for Phish 3.0 era
Elixir Phoenix LiveView D3.js
Local LLM on MacBook
4-bit quantization, safetensors, and Bumblebee + EMLX for Apple Silicon
Elixir Rust Python
A Bot that posts like me
Porting the posting bot to Elixir using local LLM work
Elixir Bumblebee EMLX
Receipt Printer Software Suite
A complete software suite for thermal receipt printers
Elixir Python
Role Call
TV writer overlap explorer
Elixir Phoenix LiveView
Fill Your Sky
Interactive map of 418+ Bluesky communities with 545K+ people
Elixir Phoenix LiveView D3.js
Code Mirror
A live code mirror experiment
Elixir Phoenix LiveView
Pocket Pnin
A local LLM running on my iPhone, coming to the App Store for free
Swift MLX
NYC Census Maps
Interactive census and PLUTO data visualization for New York City
Elixir Phoenix LiveView Leaflet.js
MTA Bus Tracker
Real-time MTA bus and train tracking on an interactive map
Elixir Phoenix LiveView Leaflet.js
Concert GIF Maker
Extract GIFs from concert videos with a retro Mac interface
Elixir Phoenix LiveView FFmpeg
Send a VERY direct message, to my receipt printer
A social project where friends send photos that print on my receipt printer
Elixir Phoenix LiveView
Archive TV
A real over-the-air TV channel from magnetic media archives
Elixir FFmpeg
Losselot
Neural network loss function explorer
Python
Todoinksies
A personal todo app
Elixir Phoenix LiveView
Ormery
An ORM written in Temper
Temper
Collage Maker
Upload photos and arrange them into grid collages
Elixir Phoenix LiveView
GenStage Tutorial 2025
A modern GenStage tutorial for the Elixir ecosystem
Elixir GenStage
Temper Rust Bug
Found a bug in the Temper compiler and built a demo repo
Temper Rust
300+ Years of Tree Law
A blog post that became its own LiveView application
Elixir Phoenix LiveView
HEEx in Other Languages
Experiments porting Phoenix HEEx templates to Rust, Lua, C#, Java, Python, and JS
Temper Rust Lua
Live Draft LSP
Live-stream blog drafts from Zed to Phoenix via a custom LSP
Rust Elixir Zed
Bluesky Hoover Apps
Various apps that vacuum up and process the Bluesky firehose
Elixir Phoenix LiveView
Bobby Posts Bot
A bot that posts like me, in Python
Python
Photo Booth Receipt Printer
A portable photo booth that prints on receipt paper
Python Elixir
Nathan For Us
A Nathan For You social network with video search and GIF creation
Elixir Phoenix LiveView FFmpeg
Browser History Roast MCP
An MCP server that roasts you based on your browser history
Python MCP
GenStage Tutorial (Original)
The original GenStage tutorial
Elixir GenStage
Bluesky Firehose Toys
Real-time firehose visualizations: emoji streams, jetstream comparisons, and more
Elixir Phoenix LiveView WebSocket
31 exhibits Apps & Games
MY FAV
LEICA SHOTS
Work Log — Recent Commits
+319-1 notactuallytreyanastasio/blimp/main Mar 21 17:40
52d5535 Merge pull request #14 from notactuallytreyanastasio/blimp-core/handler-syntax Add when guards, bubbles(), dot-notation actors
8eff600 Add when guards, bubbles() annotation, dot-notation actor names on :msg(args) when guard bubbles(Strategy) do. Dot-notation actor names: actor Shop.Checkout do. 38 tree-sitter tests. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
+339-4 notactuallytreyanastasio/blimp/main Mar 21 17:39
82440d0 Merge pull request #13 from notactuallytreyanastasio/blimp-core/message-send Add message send <- and orelse
+3996-1286 notactuallytreyanastasio/blimp/blimp-core/message-send Mar 21 17:38
433a23f Add message send <- and orelse for bubble recovery actor <- :message(args) for sending. orelse catches bubbles. Precedence: orelse lowest, then send, then binary ops. 27 Zig tests, 39 tree-sitter. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
+380-0 notactuallytreyanastasio/blimp/main Mar 21 17:35
ce9b27b Add situation keyword and _ as Hole Hole is a first-class construct: identity at runtime, agent directive via comments. situation is ambiguity-aware branching where Holes are valid. 29 Zig tests, 38 tree-sitter. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
c26666f Merge pull request #12 from notactuallytreyanastasio/blimp-core/situation-holes Add situation keyword and _ as Hole
+3281-1286 notactuallytreyanastasio/blimp/main Mar 21 17:30
dc4dca1 Add pipe operator |> (#11) * Add typed state and tree-sitter corpus tests Typed state syntax: state name: Type :: default New :: token in lexer, type_name parsing for Int/String/[Item]. Backwards compatible with untyped state. Tree-sitter corpus: 34 tests across actors, expressions, collections, statements, and complete programs. Zig parser: 21 inline tests. All green. * Add pipe operator |> with left-associative chaining Pipe parsing at lowest binary precedence. _ placeholder in pipe calls filled by pipe value. 26 Zig tests, 38 tree-sitter. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
+3766-2 notactuallytreyanastasio/blimp/term-diff/deep-look Mar 21 16:15
955fe4e wip on multiplexer
+21588-54 notactuallytreyanastasio/blimp/term-diff/tauri-desktop Mar 21 08:47
9e4556e feat: add Tauri desktop wrapper for term_diff Bundle Phoenix LiveView as a native macOS app using Tauri v2 and Burrito. Sidecar pattern: Tauri spawns the Burrito binary, polls localhost:4123 until Phoenix is ready, then navigates the webview to the LiveView. - Add Burrito dep and release config (macos_silicon target) - Configure prod for desktop: port 4123, localhost, auto-start - Remove force_ssl (desktop runs HTTP) - Scaffold Tauri v2 project at desktop/src-tauri/ - Rust lifecycle: spawn sidecar on Ready, kill on ExitRequested - Loading spinner while Phoenix boots Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
+14683-170 notactuallytreyanastasio/blimp/term-diff/liveview-integration-tests Mar 21 08:30
e5bc1ec Add 26 LiveView integration tests on real git repos Every test creates a tmp_dir git repo with commits and working tree changes, mounts DiffLive pointed at it, and exercises the full flow. Coverage: - Navigation: j/k movement, Enter/q focus, Tab toggle, log view - Stage/unstage: s stages, u unstages, rapid s/u/s/u, s from diff_view, u on unstaged-only is no-op - Commit mode: cc with nothing staged (error), cc with staged (editor), Escape exits, empty message (error), valid message (creates real commit) - Amend mode: a pre-populates message, shows amend diff, Escape/cancel exits, submit updates real commit message - Click to select, follow mode toggle, unknown keys survive, rapid multi-key sequences don't crash Also fixes diff parser crash on optional hunk header captures (nil/empty string from regex groups). 183 total tests, 0 failures. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
ea59594 Fix amend mode: pre-populate message, show last commit diff Three bugs fixed: 1. Textarea used value= attribute (ignored by browsers for textarea). Changed to inner content: <textarea>{@commit.message}</textarea> 2. Amend mode now fetches and displays the diff of the commit being amended in the right pane (full unified diff with hunks). 3. amend_diff cleared on cancel/escape/complete. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
6d1db3a note that rev-parse is in fact just already plumbing
+393-20 notactuallytreyanastasio/blimp/main Mar 21 08:30
dc4c2d8 note that rev-parse is in fact just already plumbing
9116bb9 Fix amend mode: pre-populate message, show last commit diff Three bugs fixed: 1. Textarea used value= attribute (ignored by browsers for textarea). Changed to inner content: <textarea>{@commit.message}</textarea> 2. Amend mode now fetches and displays the diff of the commit being amended in the right pane (full unified diff with hunks). 3. amend_diff cleared on cancel/escape/complete. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2f52939 Add 26 LiveView integration tests on real git repos Every test creates a tmp_dir git repo with commits and working tree changes, mounts DiffLive pointed at it, and exercises the full flow. Coverage: - Navigation: j/k movement, Enter/q focus, Tab toggle, log view - Stage/unstage: s stages, u unstages, rapid s/u/s/u, s from diff_view, u on unstaged-only is no-op - Commit mode: cc with nothing staged (error), cc with staged (editor), Escape exits, empty message (error), valid message (creates real commit) - Amend mode: a pre-populates message, shows amend diff, Escape/cancel exits, submit updates real commit message - Click to select, follow mode toggle, unknown keys survive, rapid multi-key sequences don't crash Also fixes diff parser crash on optional hunk header captures (nil/empty string from regex groups). 183 total tests, 0 failures. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
+10416-1 notactuallytreyanastasio/blimp/main Mar 21 08:12
e37cfa1 Add tooling paragraph: diff viewer, semantic diffs, time travel, reflexivity Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
6372827 ignore stuff
8ba4c79 Add blog post: The Construction of Blimp Second design journal entry walking through the grammar piece by piece. Covers actors, typed state (Type :: default), Holes as first-class agent directives, situation for ambiguity-aware branching, bubbles as supervision actors, no shared memory, and supervisor-as-namespace with both flat dot-notation and nested forms. Also updates parser.md with decisions D4-D9 from this session. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
53d7404 Riff on human-as-driver in blog post intro Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2b1f934 WIP: Blimp grammar, lexer, parser, and tree-sitter grammar Zig parser (chunks/lang/src/): - token.zig: 50+ token types with keyword lookup - lexer.zig: single-pass lexer, line/col tracking, 9 test blocks - ast.zig: tagged union AST with 16 node types - parser.zig: recursive descent with Pratt precedence, 8 test blocks - main.zig: CLI reads .blimp files, prints S-expression AST Tree-sitter grammar (chunks/lang/tree-sitter-blimp/): - grammar.js: actors, state, on/become/reply, expressions - highlights.scm: syntax highlighting queries 7 example .blimp programs all parse successfully. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
f305dee Add note about diff viewer already existing, turtles all the way down Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
92611fc add some more rules, deciduous updates
+14399-165 notactuallytreyanastasio/blimp/blimp-core/tree-sitter Mar 21 08:04
c0584ed Add blog post: The Construction of Blimp Second design journal entry walking through the grammar piece by piece. Covers actors, typed state (Type :: default), Holes as first-class agent directives, situation for ambiguity-aware branching, bubbles as supervision actors, no shared memory, and supervisor-as-namespace with both flat dot-notation and nested forms. Also updates parser.md with decisions D4-D9 from this session. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
6604bea Riff on human-as-driver in blog post intro Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
139cbef "Claude Code Review workflow"
5786222 Add tooling paragraph: diff viewer, semantic diffs, time travel, reflexivity Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
b91f327 ignore stuff
88f9fb5 add some more rules, deciduous updates
9cd97aa WIP: Blimp grammar, lexer, parser, and tree-sitter grammar Zig parser (chunks/lang/src/): - token.zig: 50+ token types with keyword lookup - lexer.zig: single-pass lexer, line/col tracking, 9 test blocks - ast.zig: tagged union AST with 16 node types - parser.zig: recursive descent with Pratt precedence, 8 test blocks - main.zig: CLI reads .blimp files, prints S-expression AST Tree-sitter grammar (chunks/lang/tree-sitter-blimp/): - grammar.js: actors, state, on/become/reply, expressions - highlights.scm: syntax highlighting queries 7 example .blimp programs all parse successfully. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
5669d74 Add note about diff viewer already existing, turtles all the way down Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
6a2b4a8 "Claude PR Assistant workflow"
+3891-166 notactuallytreyanastasio/blimp/main Mar 21 02:26
8335c10 Watch .git/index and refs for stage/commit/branch changes Watcher was ignoring ALL .git/ paths. Now watches specific git internal files: index (stage/unstage), refs/ (commits/branches), HEAD (checkout), MERGE_HEAD/REBASE_HEAD (merge/rebase). External git operations (staging from another terminal, git hooks) now trigger UI refresh automatically. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
4c7302d Add FileState state machine for git staging lifecycle Every file is in exactly one state (untracked, staged_new, unstaged_modified, staged_modified, partial_modified, etc). Each state returns the correct git command for stage/unstage via stage_command/1 and unstage_command/1. DiffLive now derives FileState from the file entry and delegates to Runner.exec_file_command/2 instead of ad-hoc conditionals. All Runner errors are logged and surfaced via put_flash. 24 new FileState tests. 142 total, 0 failures. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
69f47c7 Update build-test skill for Elixir project quality cycle Replaces cargo build/test with mix compile/test/credo pipeline. Adds TDD reminder, frontmatter metadata, and mix.exs auto-discovery. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
84b75f5 Extract CommitState pure state machine from Navigation Moves commit workflow (idle->editing->submitting->complete/error) into its own module with explicit phases. Navigation no longer tracks commit_mode/amend_mode. Errors shown inline instead of flash messages. Nothing-staged and no-previous-commit cases blocked at entry. 108 tests, 0 failures, 0 warnings. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
f399bd4 Modernize HEEx syntax and refactor submit_commit Replace <%= if/for with :if/:for attributes across all templates. Replace <%= expr %> with {expr} curly brace syntax throughout. Break nested if-inside-case in submit_commit into separate functions: execute_commit, run_git_commit, handle_commit_result. Fix alias ordering (alphabetical within groups). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
98faa5a Fix s/u keybindings: work from both file_list and diff_view stage_selected and unstage_selected were restricted to :file_list focus only. Now they fire from :diff_view too (anywhere a file is selected). Guards on nil selected_file prevent empty commands. Log_view/log_detail still no-op (no file context there). 6 new Navigation tests for s/u across focus states. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
4a19037 Add Elixir/HEEx style rules to CLAUDE.md Codifies preferences from PR #1 review: HEEx curly brace syntax, :if/:for attributes, no nested if/case, no Process.sleep in tests, one type per file, embedded Ecto schemas, supervision patterns. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
67f5c13 Fix unstage on newly added files git restore --staged fails on :added files (no prior version to restore to). Now checks staged_status: :added files use git rm --cached, :modified files use git restore --staged. DiffLive passes the file's staged_status from RepoState. Three new Runner tests covering the exact bug scenario. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
5a7898a Fix Runner stripping leading whitespace from git status output String.trim() was removing the leading space from porcelain status lines like " M file.ex", causing Status.parse to fail on files with only unstaged changes. Changed to String.trim_trailing() to preserve the significant leading column characters. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
16392f7 Add --json-schema support for forced structured JSON output Claude.build_args now accepts :json_schema option, passing --json-schema flag to claude -p for validated structured output. Prompt module defines the review schema (summary + annotations array with file, start_line, end_line, comment, severity enum). Server's default_caller passes the schema automatically. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
9abc7cf Fix Commentary.Server supervision and eliminate Process.sleep in tests Replace async_nolink with start_child + explicit message passing. Task sends {:review_complete, result} back to GenServer on completion. Tests use assert_receive instead of Process.sleep for determinism. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
61f9a8d Split Commentary.Types into one type per file Annotation, ReviewResult, FileCommentary each get their own module file under commentary/. Updated all alias references. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
d8440d2 Migrate Runner from System.cmd to Erlang Port All git commands now execute via Port.open with :spawn_executable. Supports expected_exits option for commands like diff --no-index that return exit code 1 on success. Adds 10s timeout. Includes first Runner test suite (8 integration tests with tmp_dir). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
fb7a1a5 claude touchups
31d07c1 Fix cursor drift after stage/unstage with path-based tracking Navigation.sync_to_files/2 resolves file_index from selected_file path instead of blindly trusting the index. After refresh, the cursor stays on the same file even when the list reorders. Removes ad-hoc selected_file resolution from keydown handler. The refresh handler now syncs nav to the new file list properly. 6 new tests for sync_to_files covering: path resolution, file removal, empty list, nil selected_file, list shrink clamping. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
13d528b Convert CommitState to embedded Ecto schema Uses Ecto.Enum for phase and mode fields instead of plain @type. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
3e992e9 Fix nav pipeline clobbering refreshed state after stage/unstage handle_nav_change was using the pre-stage nav, overwriting the freshly synced nav from refresh_now. Now re-reads socket.assigns.nav after handle_stage_actions so downstream steps see the real state. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2af65db Add plumbing_status/1 using diff-index, diff-files, ls-files New Runner.plumbing_status/1 returns [FileState.t()] directly from three plumbing commands instead of parsing porcelain output. Runs alongside the existing status/1 for now. 9 integration tests covering all file states: untracked, staged_new, unstaged_modified, staged_modified, partial_modified, staged_deleted, unstaged_deleted, and mixed multi-file scenarios. 157 total tests, 0 failures. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
d152c17 Remove LLMChain/CodeReviewer code entirely Deleting the Ollama-based code reviewer and langchain dependency. Will revisit AI review via claude -p CLI approach later. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
efcdeed Fix stale state after stage/unstage: synchronous refresh After a git stage/unstage command, immediately re-fetch repo state instead of relying on async send(self(), :refresh). This prevents the next keypress from seeing stale file states where a just-staged file still appears as unstaged. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
+57-12 notactuallytreyanastasio/blimp/term-diff/stage-unstage-tdd Mar 21 02:26
9c373bc Fix amend mode: pre-populate message, show last commit diff Three bugs fixed: 1. Textarea used value= attribute (ignored by browsers for textarea). Changed to inner content: <textarea>{@commit.message}</textarea> 2. Amend mode now fetches and displays the diff of the commit being amended in the right pane (full unified diff with hunks). 3. amend_diff cleared on cancel/escape/complete. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
0b8029c note that rev-parse is in fact just already plumbing
+336-8 notactuallytreyanastasio/blimp/term-diff/fix-amend-mode Mar 21 02:26
cbc418d Add 26 LiveView integration tests on real git repos Every test creates a tmp_dir git repo with commits and working tree changes, mounts DiffLive pointed at it, and exercises the full flow. Coverage: - Navigation: j/k movement, Enter/q focus, Tab toggle, log view - Stage/unstage: s stages, u unstages, rapid s/u/s/u, s from diff_view, u on unstaged-only is no-op - Commit mode: cc with nothing staged (error), cc with staged (editor), Escape exits, empty message (error), valid message (creates real commit) - Amend mode: a pre-populates message, shows amend diff, Escape/cancel exits, submit updates real commit message - Click to select, follow mode toggle, unknown keys survive, rapid multi-key sequences don't crash Also fixes diff parser crash on optional hunk header captures (nil/empty string from regex groups). 183 total tests, 0 failures. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
+68-39 notactuallytreyanastasio/blimp/term-diff/stage-unstage-tdd Mar 21 01:13
a2add80 Fix nav pipeline clobbering refreshed state after stage/unstage handle_nav_change was using the pre-stage nav, overwriting the freshly synced nav from refresh_now. Now re-reads socket.assigns.nav after handle_stage_actions so downstream steps see the real state. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
+22-3 notactuallytreyanastasio/blimp/term-diff/stage-unstage-tdd Mar 21 01:02
046d9d6 Watch .git/index and refs for stage/commit/branch changes Watcher was ignoring ALL .git/ paths. Now watches specific git internal files: index (stage/unstage), refs/ (commits/branches), HEAD (checkout), MERGE_HEAD/REBASE_HEAD (merge/rebase). External git operations (staging from another terminal, git hooks) now trigger UI refresh automatically. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
+16-4 notactuallytreyanastasio/blimp/term-diff/stage-unstage-tdd Mar 21 00:40
4d68766 Fix stale state after stage/unstage: synchronous refresh After a git stage/unstage command, immediately re-fetch repo state instead of relying on async send(self(), :refresh). This prevents the next keypress from seeing stale file states where a just-staged file still appears as unstaged. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
+187-3 notactuallytreyanastasio/blimp/term-diff/stage-unstage-tdd Mar 21 00:36
9f8b342 Add plumbing_status/1 using diff-index, diff-files, ls-files New Runner.plumbing_status/1 returns [FileState.t()] directly from three plumbing commands instead of parsing porcelain output. Runs alongside the existing status/1 for now. 9 integration tests covering all file states: untracked, staged_new, unstaged_modified, staged_modified, partial_modified, staged_deleted, unstaged_deleted, and mixed multi-file scenarios. 157 total tests, 0 failures. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
+43-5 notactuallytreyanastasio/blimp/term-diff/stage-unstage-tdd Mar 21 00:29
dc37df7 Fix s/u keybindings: work from both file_list and diff_view stage_selected and unstage_selected were restricted to :file_list focus only. Now they fire from :diff_view too (anywhere a file is selected). Guards on nil selected_file prevent empty commands. Log_view/log_detail still no-op (no file context there). 6 new Navigation tests for s/u across focus states. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
+343-16 notactuallytreyanastasio/blimp/term-diff/stage-unstage-tdd Mar 20 23:56
c6da445 Add FileState state machine for git staging lifecycle Every file is in exactly one state (untracked, staged_new, unstaged_modified, staged_modified, partial_modified, etc). Each state returns the correct git command for stage/unstage via stage_command/1 and unstage_command/1. DiffLive now derives FileState from the file entry and delegates to Runner.exec_file_command/2 instead of ad-hoc conditionals. All Runner errors are logged and surfaced via put_flash. 24 new FileState tests. 142 total, 0 failures. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
+6665-2658 temperlang/temper/do-more-crimes-to-play-snake-multiplayer Mar 20 03:57
8ed2fd4 feat: replace tungstenite with hand-rolled WebSocket over raw TCP tungstenite corrupts internal state when read/write are interleaved from different threads, even with Mutex protection. Replace it with a minimal WebSocket implementation (~150 lines) that: - Does HTTP upgrade handshake byte-by-byte (avoids BufReader read-ahead) - Uses TcpStream::try_clone() to split into independent read/write halves - Reader thread owns the read half, writer Mutex holds the write half - No shared internal framing state — reads and writes are independent - SHA-1 for the accept key via sha1_smol (only external dep) Also removes the sleep() debug logging. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
9a9b350 fix: set read timeout on WS connections for Rust backend Both server-accepted and client connections now have a 50ms read timeout. This prevents the recv loop from holding the socket Mutex indefinitely, allowing send operations to interleave. Without this, the Rust server couldn't send frames because recv blocked the lock. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
3a512b1 fix: use dedicated threads for Rust ws operations Temper's Rust runtime uses a single-threaded task runner. Blocking ws operations (accept, send, recv) would block the runner and prevent other async blocks (like readLine) from processing. Spawn dedicated threads for ws_accept, ws_send, and ws_recv instead of going through crate::run_async. This lets the WS operations block independently while other async work continues. Also adds error logging to ws_recv for debugging. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
561c49a feat: add Python backend for std/ws and std/io terminal size Wire WebSocket support (wsListen, wsAccept, wsConnect, wsSend, wsRecv, wsClose) and terminal size detection (terminalColumns, terminalRows) for the Python backend. Uses hand-rolled WebSocket over raw TCP (same approach as Rust) with socket.dup() for read/write split and a dedicated reader thread per connection. No external dependencies — just stdlib socket, hashlib, base64, struct, threading. Terminal size uses shutil.get_terminal_size(). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
936910d fix: guard wsSend against closed WebSocket connections Check readyState before calling send(), and wrap in try/catch to prevent synchronous throws from crashing the server when a client disconnects mid-broadcast. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
73b848d fix: Rust ws support - rename functions, fix visibility and stream types - Rename support functions to std_ws_* to avoid colliding with Temper-generated panic stubs (same pattern as std_sleep/std_read_line) - Change visibility from pub(crate) to pub for cross-crate access - Accept &dyn WsServerTrait/WsConnectionTrait instead of &WsServer to work with the Rust backend's interface deref codegen - Use WsStream enum to handle both WebSocket<TcpStream> (server-accepted) and WebSocket<MaybeTlsStream<TcpStream>> (client-connected) - Use temper_core::cast() for downcasting instead of manual as_any chain - Add .into() for tungstenite 0.26 Message::Text(Utf8Bytes) change Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
e76ab32 fix: add ws npm dependency to temper-core package.json The ws.js support file dynamically imports the 'ws' package, but it wasn't listed as a dependency. After temper build regenerated the output, npm install wouldn't install ws, causing wsListen/wsConnect to fail silently at runtime. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
7718c2f fix: spawn OS thread for Rust nextKeypress to avoid blocking async runner The Rust backend uses a SingleThreadAsyncRunner, so the blocking crossterm::event::read() call was starving the game tick coroutine. Spawn a real OS thread for the blocking read and complete the promise from there, allowing other async tasks to proceed concurrently. Signed-off-by: Robert Grayson <bobbbygrayson+github@gmail.com> Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> Signed-off-by: Robert Grayson <bobbbygrayson+github@gmail.com>
03f6b99 feat: add std/ws WebSocket module and std/io terminal size detection Rebased onto do-crimes-to-play-snake: resolved conflicts with std/keyboard, updated Rust terminal size to use crossterm instead of libc, added ws to stdSupportNeeders set.
d9f3020 fix: channel-based I/O for Rust WebSocket connections Replace Mutex-shared WebSocket with a dedicated I/O thread per connection that communicates via mpsc channels. The I/O thread owns the WebSocket exclusively and polls for both send and recv, avoiding tungstenite's internal state corruption from concurrent access. Send is now non-blocking (channel push), recv blocks on the channel receiver in a spawned thread. This fixes the ResetWithoutClosingHandshake error that occurred when the server's recv loop and send loop competed for the socket. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
7fceb70 test: update snapshots for io.js and keyboard.js in CLI tests JsRunFileLayoutTest: add io.js and keyboard.js to expected file trees in both std/ and temper-core/ directories. ReplTest: allow scheduler call in Lua translation output. Signed-off-by: Robert Grayson <bobbbygrayson+github@gmail.com> Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> Signed-off-by: Robert Grayson <bobbbygrayson+github@gmail.com>
9bb8efa chore: remove debug logging from Rust ws support Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
+5731-2657 temperlang/temper/do-crimes-to-play-snake Mar 19 22:22
769ab8f fix: make all 6 backends run the snake game correctly Lua: - Replace temper.TODO stub with cooperative coroutine scheduler - async {} now compiles to temper.async_launch() (was "TODO") - LuaTranslator emits temper.run_scheduler() after top-level code - Non-blocking IO: sleep uses deadline-based promises, readLine uses stty min 0 time 0 for polling - Round-robin scheduler drives multiple async blocks cooperatively Rust: - Fix missing temper-std dependency in generated Cargo.toml - Connected functions (stdSleep, stdReadLine) reference temper_std:: paths but bypassed the import-based dependency scan - RustTranslator now tracks usedSupportFunctionPaths - RustBackend scans these after translation to inject temper-std dep with correct features - Also fixes missing temper_std::init() in generated lib.rs - Add raw terminal mode for single-keypress input Java: - Fix waitUntilTasksComplete() 10-second hard timeout - Now loops until ForkJoinPool is truly quiescent - Add raw terminal mode via stty for single-keypress input C#: - Update target framework from net6.0 to net8.0 (current LTS) - Namespace-qualify OrderedDictionary and AsReadOnly in RegexSupport.cs to avoid conflicts with System.Collections.Generic.OrderedDictionary introduced in .NET 9+ - Add single-keypress input via Console.ReadKey Python: - Add raw terminal mode for single-keypress input via tty/termios Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
4d44c8f be-lua: debug shift operator wrappers Signed-off-by: Mike Samuel <mikesamuel@gmail.com>
a3fa212 specialize lua bitops so we can mask shift distances Signed-off-by: Mike Samuel <mikesamuel@gmail.com>
70b29ea TokenSourceAdapter works with margin characters Signed-off-by: Mike Samuel <mikesamuel@gmail.com>
09dfee2 remove debug cruft Signed-off-by: Mike Samuel <mikesamuel@gmail.com>
53e5d99 fix test goldens Signed-off-by: Mike Samuel <mikesamuel@gmail.com>
91cebe8 astbuild: Reworked expression inversion for MQ strings Previously, TokenSourceAdapter assumed brackets, (`{:` ... `:}`) around statement fragments. Now we have margin characters that, in a left to right scan, give enough context. This reworks *TokenSourceAdapter* to cue off the margin characters when inverting statements in complex string expressions, and to differentiate between `~` and `"` margin characters when stripping incidental whitespace. It also updates documentation around string expression syntax, semantics, and whitespace elision. Signed-off-by: Mike Samuel <mikesamuel@gmail.com>
6d83930 Define missing shift and bitwise operators (#375) Previously, Temper was missing some bit-twiddling operators: - Shift operators: `<<`, `>>`, and `>>>`. - Bitwise negation: `~` - Exclusive or: `^` In keeping with JavaScript for syntactic choices, this commit defines these operators with that punctuation. Unlike JavaScript, our semantics are the same as C-like languages that do not have undefined behaviour on over/under flow, e.g. Java and C#. This commit also defines a functional test that exercises these operators. Some bugs were flushed out as a result: - C#'s *System.Text.Convert.ToString* when used to format numbers as non-decimal, formats as if cast to unsigned: no `-` sign for negative numbers. - be-js does not always render *Int64*s as bigints. - Lua's number formatting ran into trouble with *math.mininteger* because of the 2's complement fixed point around negation with the smallest representible integer. ## Caveat ~~Lua, Rust, and C++ do not currently pass. This commit will remain as part of a draft PR until they do.~~
4d4c3d0 fix: simplify readLine to actual line reading across all 6 backends Address PR review feedback: readLine was doing raw TTY single-keypress reading instead of actual line reading. This simplifies all backends to do buffered line input, removes all process-exit calls (System.exit, process.exit, os.kill, Environment.Exit), fixes the Java completeExceptionally bug, and reverts the incidental net8.0 bump in the C# csproj back to net6.0. The keyboard/keypress functionality will be provided by a separate std/keyboard module. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> Signed-off-by: Robert Grayson <bobbbygrayson+github@gmail.com>
eafa620 ran code formatter Signed-off-by: Mike Samuel <mikesamuel@gmail.com>
6d734c4 be-lua: number formatting with base Signed-off-by: Mike Samuel <mikesamuel@gmail.com>
92fd175 lexer: Lex new multi-line string context. This commit enables the new margin character based syntax. It removes support for `{:...:}` lines, and recognizes `:` and `~` as margin characters where the former allows for open tokens like the others. This commit adds TokenType info when managing the delimiter stack so that we can make clear distinctions between `"` as a left delimiter, a right delimiter, or a margin character. It also reworks regex literal syntax to use left and right delimiters to avoid ambiguity in later passes with `/foo/i` as a quoted string segment on a margin line. This commit also simplifies TokenClusterTest to, instead of emulating the delimiter stack and saved element stack, to instead interrogate the Lexer using internal `*ForDebug` methods. The nesting levels of synthesized tokens look less pretty, but it matches what updateTokenClusters and popDelimiterStack actually do. Signed-off-by: Mike Samuel <mikesamuel@gmail.com>
4bc8ccc Avoid parse fail on old luas Signed-off-by: Tom <tom@contextfree.info>
97a2086 be-cpp: unsigned right shifting support Signed-off-by: Mike Samuel <mikesamuel@gmail.com>
6707857 fix test golden from adding int.js as a supporting file Signed-off-by: Mike Samuel <mikesamuel@gmail.com>
4519f5d lexer: ensure we do not reset the content line hint inside an interpolation Signed-off-by: Mike Samuel <mikesamuel@gmail.com>
75ad3c0 parse: fix OPP test cases for new regex/mq-string syntax and lexing conventions Signed-off-by: Mike Samuel <mikesamuel@gmail.com>
9c68c81 release-notes: breaking change warning re string syntax. Signed-off-by: Mike Samuel <mikesamuel@gmail.com>
70c75bb test: add functional test for `std/io` `sleep()` across backends Adds `control-flow/io-sleep/io-sleep.temper.md` to the functional test suite, verifying that `sleep()` from `std/io` works correctly: - Sleep returns and execution continues after `await` - Multiple sequential sleeps work - Zero-ms sleep resolves immediately - Sleep interleaved with computation produces correct results Uses short delays (5-10ms) to avoid slowing the test suite. Passes on: JS, Python, Lua, Java 17, C#. Skipped on Rust (`@Ignore`) because the Rust functional test infrastructure only links `temper-core`, not `temper-std`, so `import("std/io")` produces an unresolved crate at cargo build time. The Rust `sleep` implementation itself works (verified manually via the snake game with `cargo run`). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1650f8b Define missing shift and bitwise operators Previously, Temper was missing some bit-twiddling operators: - Shift operators: `<<`, `>>`, and `>>>`. - Bitwise negation: `~` - Exclusive or: `^` In keeping with JavaScript for syntactic choices, this commit defines these operators with that punctuation. Unlike JavaScript, our semantics are the same as C-like languages that do not have undefined behaviour on over/under flow, e.g. Java and C#. This commit also defines a functional test that exercises these operators. Some bugs were flushed out as a result: - C#'s *System.Text.Convert.ToString* when used to format numbers as non-decimal, formats as if cast to unsigned: no `-` sign for negative numbers. - be-js does not always render *Int64*s as bigints. - Lua's number formatting ran into trouble with *math.mininteger* because of the 2's complement fixed point around negation with the smallest representible integer. ## Caveat Lua, Rust, and C++ do not currently pass. This commit will remain as part of a draft PR until they do. Signed-off-by: Mike Samuel <mikesamuel@gmail.com>
085161f chore: add stdReadLine and stdSleep to connected list in README Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> Signed-off-by: Robert Grayson <bobbbygrayson+github@gmail.com>
ac4ef18 feat: add std/io module with sleep() and readLine() across 6 backends This commit adds two new @connected primitives to Temper's standard library — sleep(ms) and readLine() — wired across all six compilation backends: JavaScript, Python, Lua, Rust, Java, and C#. These are the first I/O primitives in Temper that enable interactive, real-time programs to be written entirely in the Temper language without any host-language wrapper scripts. The motivation: a snake game written in pure Temper needed a game loop that ticks every 200ms. Previously, Temper had no way to pause execution or read user input. The only I/O primitive was console.log(). Programs could compute and print, but could not wait or listen. This meant any interactive program required a host-language wrapper (a Node.js script, a Python script, etc.) to drive the game loop with setTimeout or time.sleep, calling into the compiled Temper module from outside. With sleep() and readLine(), a Temper program can now do this: let {sleep} = import("std/io"); async { (): GeneratorResult<Empty> extends GeneratorFn => do { var game = newGame(20, 10, 42); while (game.status is Playing) { game = tick(game); console.log(render(game)); await sleep(200); } } orelse void; } That code compiles and runs identically on JS, Lua, Rust, Java, and Python (via temper run). No wrapper. No FFI. One source, six targets. --- THE ARCHITECTURE --- Temper's @connected decorator system is the bridge between portable Temper code and backend-specific native implementations. A connected function has a Temper declaration with a panic() body that is never executed — the compiler intercepts the call and routes it to a native implementation registered in the backend's SupportNetwork. The wiring for each connected function follows a 4-layer pattern: 1. Temper declaration: @connected("key") in a .temper.md file 2. Kotlin SupportNetwork: registers the key in the backend compiler 3. Runtime implementation: actual native code (.js, .py, .lua, .rs, etc.) 4. Resource registration: tells the build system to bundle the file This commit touches all four layers for all six backends. --- THE TEMPER DECLARATION (frontend) --- A new std/io module is created at: frontend/.../std/io/io.temper.md It declares two functions: @connected("stdSleep") export let sleep(ms: Int): Promise<Empty> { panic() } @connected("stdReadLine") export let readLine(): Promise<String?> { panic() } Key design decisions: - sleep() returns Promise<Empty>, not Promise<Void>. This is because Temper's await builtin requires the promise's type parameter to extend AnyValue, and Void does not. Empty is a singleton class that does extend AnyValue, so Promise<Empty> is the correct return type for a "returns nothing meaningful" async operation. - readLine() returns Promise<String?>, nullable because EOF returns null. - The bodies are panic() — a convention matching stdNetSend in std/net. The @connected decorator ensures the body is never reached; the backend substitutes its own implementation at compile time. The std config (std/config.temper.md) gains import("./io") to include the new module in the standard library. --- JAVASCRIPT BACKEND (be-js) --- Files changed: - be-js/.../temper-core/io.js (NEW) - be-js/.../temper-core/index.js (export added) - be-js/.../JsBackend.kt (resource registered) - be-js/.../JsSupportNetwork.kt (keys added to supportedAutoConnecteds) The JS backend uses the "auto-connected" pattern: connected keys listed in the supportedAutoConnecteds set are automatically mapped to exported functions whose names follow the connectedKeyToExportedName convention. "stdSleep" maps to an exported function named stdSleep in io.js. The implementation: export function stdSleep(ms) { return new Promise(resolve => setTimeout(() => resolve(empty()), ms)); } This returns a native JS Promise that resolves after ms milliseconds via setTimeout. It resolves with empty() (the Temper Empty singleton) to match the Promise<Empty> return type. readLine() returns a Promise that reads from process.stdin via the 'data' event, or resolves with null if stdin is unavailable (browser). --- PYTHON BACKEND (be-py) --- Files changed: - be-py/.../temper_core/__init__.py (functions added) - be-py/.../PySupportNetwork.kt (PySeparateCode + pyConnections) Python's async model uses concurrent.futures.Future with a ThreadPoolExecutor. The existing _executor and new_unbound_promise() infrastructure (already used by stdNetSend) is reused: def std_sleep(ms): f = new_unbound_promise() def _do_sleep(): time.sleep(ms / 1000.0) f.set_result(None) _executor.submit(_do_sleep) return f The sleep happens on a worker thread; the Future resolves when done. The main thread's generator-based coroutine system picks up the resolution via the existing _step_async_coro machinery. Python programs run via `temper run --library snake -b py`, which generates an entry point that calls await_safe_to_exit() to keep the process alive until all async tasks complete. --- LUA BACKEND (be-lua) --- Files changed: - be-lua/.../temper-core/init.lua (functions + async stub added) Lua is the most interesting case. It has no Promises, no event loop, and no async/await. The Lua translator compiles: - async { ... } → temper.TODO(generatorFactory) - await expr → expr:await() Previously, temper.TODO was undefined (hitting the __index metamethod fallback which errors with "bad connected key: TODO"). This commit adds a minimal stub: function temper.TODO(generatorFactory) local gen = generatorFactory() local co = gen() end This creates the generator and steps it once via coroutine.wrap(), which runs the entire body synchronously (since all awaited operations complete immediately in Lua). For sleep and readLine, the functions are synchronous and return a table with an :await() method so the compiled await translation works: local function make_resolved(value) return { await = function(self) return value end } end function temper.stdsleep(ms) local sec = ms / 1000 local ok, socket = pcall(require, "socket") if ok then socket.sleep(sec) else os.execute("sleep " .. string.format("%.3f", sec)) end return make_resolved(nil) end The sleep implementation tries LuaSocket first (sub-second precision), falling back to os.execute("sleep ...") on systems without it. The naming convention: the default else clause in LuaSupportNetwork's translateConnectedReference converts "stdSleep" to "stdsleep" via .replace("::", "_").lowercase(), which matches temper.stdsleep(). No Kotlin changes needed for Lua. --- RUST BACKEND (be-rust) --- Files changed: - be-rust/.../std/io/support.rs (NEW) - be-rust/.../RustBackend.kt (feature + stdSupportNeeders) - be-rust/.../RustSupportNetwork.kt (FunctionCall entries) Rust uses a custom async runtime (not tokio) based on Promise<T>, PromiseBuilder<T>, and SafeGenerator<T>. The pattern matches stdNetSend exactly: create a PromiseBuilder, spawn async work via run_async(), complete the promise from the worker. pub fn std_sleep(ms: i32) -> Promise<()> { let pb = PromiseBuilder::new(); let promise = pb.promise(); crate::run_async(Arc::new(move || { let pb = pb.clone(); SafeGenerator::from_fn(Arc::new(move |_| { std::thread::sleep(Duration::from_millis(ms as u64)); pb.complete(()); None })) })); promise } The connected reference uses full crate paths ("temper_std::io::std_sleep") because the function lives in the std crate but is called from user crates. The "io" feature is added to stdSupportNeeders and the generated Cargo.toml as io = [] (no external dependencies — only std library). --- JAVA BACKEND (be-java) --- Files changed: - be-java/.../temper/core/Core.java (methods added) - be-java/.../JavaSupportNetwork.kt (separateCode + connections) - be-java/.../StandardNames.kt (qualified names) Java maps Temper Promises to CompletableFuture<T>. The stdSleep implementation runs Thread.sleep on the ForkJoinPool: public static CompletableFuture<Optional<? super Object>> stdSleep(int ms) { CompletableFuture<Optional<? super Object>> future = new CompletableFuture<>(); ForkJoinPool.commonPool().execute(() -> { Thread.sleep(ms); future.complete(Optional.empty()); }); return future; } The return type is CompletableFuture<Optional<? super Object>> because Temper's Empty type maps to Tuple<object?> (via the connectedTypes map), and the generated Java code declares the variable as such. --- C# BACKEND (be-csharp) --- Files changed: - be-csharp/.../std/Io/IoSupport.cs (NEW) - be-csharp/.../CSharpBackend.kt (resource registered) - be-csharp/.../CSharpSupportNetwork.kt (StaticCall entries) - be-csharp/.../StandardNames.kt (namespace + member names) C# has native async/await with Task<T>, making this the most natural fit. The implementation uses Task.Delay for non-blocking sleep: public static async Task<Tuple<object?>> StdSleep(int ms) { await Task.Delay(ms); return Tuple.Create<object?>(null); } The return type is Task<Tuple<object?>> because C# maps Temper's Empty to System.Tuple (via the connectedTypes map entry "Empty" -> systemTuple). --- VERIFICATION --- All backends compile. Tested with a snake game (18 unit tests passing on JS backend, game loop running on JS, Lua, Rust, Java, and Python): JS: node temper.out/js/snake/index.js Lua: cd temper.out/lua && lua snake/init.lua Rust: cd temper.out/rust/snake && cargo run Java: javac + java -cp build snake.SnakeMain Python: temper run --library snake -b py C#: dotnet build succeeds (needs net6.0 runtime to execute) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
8b168f6 be-lua: implement intold shifts based on div/mult by pow(2) Signed-off-by: Mike Samuel <mikesamuel@gmail.com>
86d4ee7 regenerated docs and fixed a test Signed-off-by: Mike Samuel <mikesamuel@gmail.com>
6ed791d Avoid parse fail on old luas (#381) - This doesn't actually fix the int shifty funtest on old luas, but from manual testing, I *can* run the int limits funtest without crashing on both luajit and lua 5.2 (but not 5.1, but maybe that was an existing issue?) with these changes. - Before these changes, old luas don't run at all for any funtest - Here's the error on plain 5.1: ```lua C:\Users\tjpal\Apps\lua-5.1.5_Win64_bin\lua5.1.exe: .\temper-core/intold.lua:38: attempt to call field 'trunc' (a nil value) stack traceback: .\temper-core/intold.lua:38: in function 'rshift' .\temper-core/intold.lua:64: in function 'int32_mul_parts' .\temper-core/intold.lua:199: in function 'int32_mul' .\work\init.lua:10: in main chunk [C]: ? ```
2062ade be-rust: use wrapping versions of shift on Rust to avoid panics on over/under-flow Signed-off-by: Mike Samuel <mikesamuel@gmail.com>
133c620 feat: add std/keyboard module with nextKeypress() across 6 backends New std/keyboard module separate from std/io, providing single-keypress input for interactive programs like the snake game. API: nextKeypress(): Promise<String?> returns key names as strings ("a", "ArrowUp", "Enter", "Escape", etc.) or null on EOF. Backend implementations: - Java: stty raw mode (Unix) + PowerShell ReadKey (Windows) - JavaScript: Node setRawMode with escape sequence parsing - Python: tty/termios (Unix) + msvcrt (Windows) - Lua: cooperative scheduler with poll_char and PROMISE_KEYPRESS state - C#: Console.ReadKey with ConsoleKey enum mapping - Rust: crossterm crate for cross-platform keypress reading Windows support on 5/6 backends (Lua is Unix-only for now). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> Signed-off-by: Robert Grayson <bobbbygrayson+github@gmail.com>
22 pushes github.com/notactuallytreyanastasio
phangraphs — Phish 3.0 Jam Analytics
phangraphs
What's Going Through Your Mind
.500
BATTING AVG
8 JC · 16× played
Avg 16.6m · Peak 42:40 · 🎧 11/16
Longest: 42:40
2025-06-24 · Petersen Events Center
Most Loved: 18 likes
2024-12-31 · Madison Square Garden
📊 88% Set 2 · 7/8 JCs from Set 2
Last: 2026-01-29 (51d ago) · avg every 36d
Best year: 2024 — 4/5 JC
"Debut. Features Billy Strings on guitar and added vocals (and a nice jam, too)."
TAP TO SEE AND PLAY JAMS
What's Going Through Your Mind .500
TAP TO FLIP BACK
8 jams
2024-08-07 10:29
Van Andel Arena · Grand Rapids, MI
Debut. Features Billy Strings on guitar and added vocals (and a nice jam, too).
2024-08-15 23:05
The Woodlands · Dover, DE
Nothing green here. With Trey back on lead vocals, a great version of the song breaks from what already seems like a signature lick to spark a huge jam. About seven minutes in, sound swells to inform that patterned bounce, and then the effects kick in, with Page laying heavy on his synths. Play coasts before, as one, the four become more active, propelling the play. Trey shears blocks of sound, an impossibly cool pattern, one that, on Fish's back beat, builds to a thrilling conclusion.
2024-08-31 16:34
Dick's Sporting Goods Park · Commerce City, CO
Question isn't when, but if "WGTYM?" won't jam. Seems improbable, given Trey's line from the vocal section is, like a drug, seemingly designed to bring the band back for more. Impressive, extended, synth-heavy improv runs to break for a very notable -> into "Crosseyed."
2024-12-31 17:14
Madison Square Garden · New York, NY
The centerpiece of the NYE '24 extravaganza with additional backing vocals, the jam takes a drastic turn into EDM, a genre heretofore unexplored on the Phish stage, and is interspersed with vocal quotes from several other Phish tunes (see setlist notes) before finally crashing -> into "CDT".
2025-02-01 ?
Moon Palace · Quintana Roo, Cancun, Mexico
The first post-EDM version of "WGTYM" is a distinctly slower version of the song. However, the jamming out of the song remains top-notch. Fish takes the reins initially leading a driving, percussive jam. This later gives way to a feel-good explosion of jubilant play that evokes Phish on a beach. The band eventually winds its way back to the "Mind, mind, mind," refrain.
2025-06-24 42:40
Petersen Events Center · Pittsburgh, PA
-> from a fun "YEM". Given how strong its jamming was from the first few versions played, it may have seemed inevitable a HUGE version would appear. This 40 minute masterpiece is just that. Moving from section to section with deftness and poise. Clearly, the band feels comfortable jamming this song, and this may be the cream of the "WGTYM" crop. Must-hear.
2025-07-18 28:07
United Center · Chicago, IL
Though Trey hints early on that the answer to the question may be that there is "nobody home", there's actually plenty to discover in this wide ranging version that finds the band locking on to a handful of memorable progressions, moving seamlessly between sections, and soaring over peaks before accelerating through groove laden depths to deliver a sustained and fiercely rocking finale that eventually finds itself becoming suddenly "Crosseyed".
2025-09-14 17:34
Coca-Cola Amphitheater · Birmingham, AL
> from a AWOH. Patient, rhythmic, and hypnotic; the band takes an approach here that, while it feels familiar, is interpreted through the fresh lens of the past handful of years' inventive play and that occupies a space halfway between aggression and ambience. Fans of peak free exploration will want to seek out this version.
phangraphs Phish 3.0 Jam Analytics
AIM Chat - Terminal
Online (0)
jeff 02:52 AM
What is up y'all
jeff 03:44 AM
Thanks for visiting my website
jeff 03:51 AM
Trying from mobile let’s see what’s up
Uechi Nerd 03:54 AM
Hi, greetings from Planet Crackpot!
jeff 03:55 AM
oh man what's up
jeff 03:56 AM
Hey everyone
Uechi Nerd 03:56 AM
winding down with a beer or three
Uechi Nerd 03:57 AM
desktop version
Uechi Nerd 04:01 AM
Disappointed that War does not lead to actual combined-arms conflict.
jeff 04:01 AM
that would be hard to conjure
jeff 04:02 AM
I am so excited that this works and is a successful combination of windows and old apple lol
Uechi Nerd 04:02 AM
Probably for the best, actually. That shit is very very messy.
Uechi Nerd 04:02 AM
I am intrigued and happy it works!
Uechi Nerd 04:03 AM
I respect the wizardry.
Visitor7804 04:05 AM
this is delightful.
jeff 04:06 AM
hell yeah visitor 7804, this is livin' brother
guy4get 04:07 AM
i've never felt so alive
EarlofVincent 04:09 AM
Commencing experiment in 3....2....
jeff 04:14 AM
1
leah 04:16 AM
hi!
leah 04:16 AM
this is lovely
jeff 04:21 AM
hi! lol I was just like what if I combined Mac and windows and added a flower tree of life and called it my homepage and then smoked some weed and made it happen in an empty mall in Connecticut
B. Droptables 10:51 AM
Always cool to play with your toys.
Visitor1128 08:47 AM
yo!
Visitor1128 08:48 AM
i can barely work my phone. what am i doing here?
jeff 09:04 AM
the phone is not optimized yet but it "kind of works" I am sorry lol
jeff 09:04 AM
you have to pick a username, then it goes to the chat, then if you hit the bottom tabs it'll let you go to the app sections.
Bobdawg 04:43 AM
Hi everybody this is my blog I hope you enjoy it I did some more changes and anyone can write a post here now for me.
dinkleberg 01:45 AM
ALL HAIL TREE OF LIFE
jeff 08:55 PM
hi Hacker News
jeff 04:28 PM
hey there I am not really Jeff
Mal Function 05:34 PM
Hey! Please reveal... how exactly do I actually use losselot on my Mac? I've run the git clone commend in Terminal.app and seem successfully to have installed into a new <losselot> sub-folder in my home folder but now???