They started with Ink but have since switched to their own renderer:
> We originally built Claude Code on Ink, a React renderer for the terminal. [...] Over the past few months, we've rewritten our rendering system from scratch (while still using React).
React is just an abstraction of a State -> View function.
While not universally applicable, it's very convenient during development to focus on State without thinking about View, or focus on View without thinking about State.
The concept itself has nothing to do with the actual renderer: HTML, TUI, or whatever. You can render your state to a text file if you want to.
So the flickering is caused either by a faulty renderer, or by using a render target (terminal) that is incompatible with the UI behavior (frequent partial re-renders, outputting a lot of text etc.)
Thats the problem. Some developers want to avoid learning another programming language and use one for everything (including their technologies.)
Using TS, React here doesn’t make sense for stability in the long term. As you can see, even when they replaced Ink and built their own, the problem still exists.
There are other alternatives that are better than whatever Anthropic did such as Bubbletea (Go) or Ratatui (Rust) which both are better suited for this.
Maybe they were thinking more about job security with TypeScript over technical correctness and a robust implementation architecture and this shows the lack of it.
I’m a fan of Bubbletea, but it is significantly less ergonomic than React. Although I’d argue that if that starts to matter significantly, your TUI is probably too cluttered anyway and you should pare it down.
> They have the technical means to control what goes on there or not.
They have less control than you may think.
Any ethereum miners (or proof-of-stake validators) who block some class of transactions immediately become vulnerable to denial of service attacks.
This came up back in 2016 with the DAO hack on ethereum[1]. Some ethereum miners considered blocking transactions that moved the stolen funds, but then realized that this was infeasible: if you block such transactions, then the DAO hacker can spam you with them. Such spam on ethereum is usually prevented by requiring the sender to spend money on each transaction (ie pay gas fees). But that fee is only charged when the transaction is included in a block -- if you refuse to include it, then the spammer pays nothing. The kicker is that, by Rice's theorem, there is no way in general to distinguish "malicious" transactions from non-malicious ones (for _any_ definition of "malicious") short of just executing them to see what they do.
So if you as an ethereum miner (or validator) try to block certain transactions, you can be forced to do unbounded amounts of work for free, ie DoS'd.
I do subscribe to channels and my feed is also flooded with these scams. (Though usually it is not this bad -- it got much worse starting on the day of SpaceX's Inspiration 4 launch.)
I'm assuming the algorithm is showing them to me because I watch lots of SpaceX and other space videos. The descriptions in these videos are even ripped directly from legit videos that I actually watched!
You're not the only one. I've been getting annoyed by these, too.
I was encouraged today to discover that youtube has a report history page that lets you know the outcome of your reports. Most of the videos I've reported have been removed, including most of the ones I've reported in the last 12 hours. So at least _something_ is being done about them, even though the current effort is not sufficient against the unending inflow of new scam videos.
Excellent. Good to see all the ones I reported have been removed. That gives me a lot more confidence in the reporting mechanism. Youtube is obviously dealing with a considerable volume of these. I still wonder if I am being used as a mechanical turk to help identify these. Hopefully the inputs are training a machine learning system.
LiteIDE was probably using gdb as a backend. gdb is not a very reliable debugger as of the last few Go releases. Here's a demo of a common failure mode of gdb on Go: occasionally running the entire program when you try to take a single step https://youtu.be/qo4RAPxCTa0?t=351
This failure mode is a large part of why I decided to write godebug.
"Also, having the debugging library alter the semantics of the program is 100% guaranteed to lead to bugs that are not visible when using the library, etc"
Can you give an example of the kind of bug you expect to see?
Sure, i'll stick to bugs invisible with the library, and visible without it:
If you've inserted compiler barriers it can't move code across, the compiler will no longer perform the same optimizations with and without your debug library.
Those optimizations often make bugs visible, because variables no longer have the value you expect them to at the time you expect it, etc.
Look at the behavior this has with and without the barrier.
It's buggy without it. With it, it's fine.
This is exactly equivalent to:
Without the debugging library, the code is clearly buggy and doesn't work in user-visible ways.
With the debugging library, if i insert a breakpoint where the current asm barrier is, it now behaves correctly 100% of the time, even though it's broken.
You set a breakpoint on the call to bar and examine the value of x. You would expect it to be 2, but what if the compiler had decided to move the allocation of x = 2 to after the call to bar? There's no reason why it shouldn't. You'd then see x = 1, which would confuse you.
But it's not really material, because bar doesn't touch x (and if it did, this problem wouldn't exist to begin with).
In other words, it might be a bit strange and cause a slight detour in your quest to discover the cause of a bug, but it wouldn't actually change any behavior or cause any issues.
Your argument is essentially: The barriers you insert, even if they block optimization, will never block optimization in a way that changes behavior. This is demonstrably false, since you are, among other things, taking the address of a variable, which means escape analysis won't do things to it, etc.
You can argue "The behavior it changes doesn't matter". As i've shown,
1. it does in a threaded environment (like, you know, go)
2. It depends on whether your code is buggy or not.
IT's certainly true that it never, on it's own, causes bugs.
But as i've shown, it can make bugs appear to come or go.
If you don't think that will ever happen, i don't know what to tell you, other than "It has happened in literally every compiler that has ever had barriers like this".
Without any evidence why Go should be different here, i don't see why go will be different here.
Thanks! gopherjs is a really great project. This was my first time using it and I was impressed.
I've considered putting it up as a permanent playground like http://play.golang.org, where you can debug little Go snippets on the web. Is that something that you would find useful?
I agree with you about gopherjs being an awesome project. And I would love to see a playground-like debugger that you could run directly in your browser for quick debugging!
Author here. Yes, only one goroutine is paused at a time. I'm planning to add commands to show and jump between goroutines. Still sketching those out, though. Do you think it would be helpful to have multiple goroutines paused by the debugger at once?
I'd like to be able to completely pause all goroutines and slowly analyze the state of each one. You can probably just add some mutex or waitgroup to your line() method and just lock it when a goroutine pauses, no?
Yeah, that should be relatively easy to do. We would just skip the "am I the goroutine under the debugger" check here [1] and add some kind of channel communication here [2]. The hardest thing is probably just the UI. How should that functionality work? I'm imagining something like this:
>>> pause all
All goroutines paused
>>> show goroutines
1: foo.go:16
2: foo.go:24
3. bar.go:10 [current]
>>> next
-> // some code from goroutine 3
>>> goroutine 2
Now tracing goroutine 2. Current location:
/*
Code listing from goroutine 2's current location
*/
>>> next
-> // some code from goroutine 2
In a well behaved program, all theads should probably be synchronized by mutexes/channels etc, so pausing one thread, should in theory pause all related ones.
I tried using this facility a few months ago based on this very short documentation but couldn't get it working, nor could I search out any further doco on it, so because it wasn't really important I gave up. Can I ask... have any of you ever successfully used this?
> We originally built Claude Code on Ink, a React renderer for the terminal. [...] Over the past few months, we've rewritten our rendering system from scratch (while still using React).
https://github.com/anthropics/claude-code/issues/769#issueco...