> Looking at linode, those prices get you an instance with 1Gb of ram and a mediocre CPU. So you are running all of your applications on that?
I ran a LoB webapp for multiple companies on a similar setup. Turns out 1GB of RAM is insufficient to run even the most trivial Java webapps, like Jenkins, but is more than sufficient for even non-trivial things using Go + PostgreSQL.
It's a good point, but I don't think the problem here is Claude. It's how you use it. We need to be guiding developers to not let Claude make decisions for them. It can help guide decisions, but ultimately one must perform the critical thinking to make sure it is the right choice. This is no different than working with any other teammate for that matter.
That's not helped by a recent change to their system prompt "acting_vs_clarifying":
> When a request leaves minor details unspecified, the person typically wants Claude to make a reasonable attempt now, not to be interviewed first. Claude only asks upfront when the request is genuinely unanswerable without the missing information (e.g., it references an attachment that isn’t there).
> When a tool is available that could resolve the ambiguity or supply the missing information — searching, looking up the person’s location, checking a calendar, discovering available capabilities — Claude calls the tool to try and solve the ambiguity before asking the person. Acting with tools is preferred over asking the person to do the lookup themselves.
> Once Claude starts on a task, Claude sees it through to a complete answer rather than stopping partway. [...]
In my experience before this change. Claude would stop, give me a few options and 70% of the time I would give it an unlisted option that was better. It actually would genuinely identify parts of the specs that were ambiguous and needed to be better defined. With the new change, Claude plows ahead making a stupid decision and the result is much worse for it.
I actually noticed the same. Having it work on Mithril.js instead of React seems (I know it's all just kind of hearsay) to generate a lot cleaner code. Maybe it's just because I know and like Mithril better, but also is likely because of the project ethos and it's being used by people who really want to use Mithril in the wild. I've seen the same for other slightly more exotic stacks like bottle vs flask, and telling it to generate Scala or Erlang.
That makes sense. There's less training data but it is better training data. LLMs were trained on really bad pandas code, so they're really really good at generating bad pandas. Elixer, there's less of it, but what there is, is higher quality, so then what it outputs is off higher quality too.
I think if you believe that you're either lying or experiencing psychosis. LLMs are the greatest innovation in information retrieval since PageRank but they are not capable of thought anymore than PageRank is.
Shouldn’t Claude just refuse to make decisions, then, if it is problematic for it to do so? We’re talking about a trillion dollar company here, not a new grad with stars in their eyes
I have a smattering of books on Kindle, mostly fiction/novels. But the vast majority of my book conllection consists of non-fiction/textbooks and I recently switched to Booklore on my NAS. I have over 900 textbooks and can access them anywhere via a WireGuard VPN. It's so slick!
Booklore seems great, but I'll admit there may be even better options. However this is the future of books for me. I'd like to start replacing more and more of my physical books with pdf/epub copies. It's been hard because there is nothing I love more than sitting down with a physical book. But this is definitely far more convenient.
I now want to start building up a research paper library in the same system.
There was some whole blowup with Booklore over it being vibecoded by a single maintainer recently. I think the project has changed ownership since then, but be cautious.
I use Calibre + Calibre Web. Definitely a bit old and clunky, but reliable.
Booklore was nuked by the maintainer after the blowup and no longer exists. Mostly it was not vibecoded, just the last few releases. The other contributors have since forked it as grimmory and have already done a first release that removes the telemetry etc. Grimmory is great imo and seems to be in good hands now.
I wish there was a way to add books to a ‘shelf’ (a collection, which you can sync to a device) without having to open each book and add.
I want to go Select + Select + Select > Add > Sync.
Agreed on your take on the parent, although I have to say I feel that AI has had the opposite effect for me. It has only accelerated learning quite significantly. In fact not only is learning more effective/efficient, I have more time for it because I am not spending nearly as much time tracking down stupid issues.
> I have more time for it because I am not spending nearly as much time tracking down stupid issues.
It is a truism that the majority of effort and time a software dev spends is allocated toward boilerplate, plumbing, and other tedious and intellectually uninteresting drudgery. LLMs can alleviate much of that, and if used wisely, function as a tool for aiding the understanding of principles, which is ultimately what knowledge concerns, and not absorbing the mind in ephemeral and essentially arbitrary fluff. In fact, the occupation hazard is that you'll become so absorbed in some bit of minutia, you'll forget the context you were operating in. You'll forget what the point of it all was.
Life is short. While knowing how to calculate mentally and/or with pen and paper is good for mastering principles and basic facility (the same is true of programming, btw), no one is clamoring to go back to the days before the calculator. There's a reason physicists would outsource the numerical bullshit to teams of human computers.
Sounds like you're talking about research AI and not generative AI. You can't learn artistic/creative techniques when you're not practicing those techniques. You can have a vision, but the AI will execute that vision, and you only get the end result without learning the techniques used to execute it.
Okay, this is a pet peeve of mine, so forgive me if I come off a little curt here, but-- I disagree strongly with how this was phrased.
"Generative AI" isn't just an adjective applied to a noun, it's a specific marketing term that's used as the collective category for language models and image/video model -- things which "generate" content.
What I assume you mean is "I think <term> is misleading, and would prefer to make a distinction".
But how you actually phrased it reads as "<term> doesn't mean <accepted definition of the term>, but rather <definition I made up which contains only the subset of the original definition I dislike>. What you mean is <term made up on the spot to distinguish the 'good' subset of the accepted definition>"
I see this all the time in politics, and it muddies the discussion so much because you can't have a coherent conversation. (And AI is very much a political topic these days.) It's the illusion of nuance -- which actually just serves as an excuse to avoid engaging with the nuance that actually exists in the real category. (Research AI is generative AI; they are not cleanly separable categories which you can define without artificial/external distinctions.)
That's a really useful distinction to have explicitly articulated. It's also why plan mode feels like a super power. Research vs Generative AI are different: I'm going to use this.
I guess I was more referring to just using generative AI when learning new subjects and exploring new ideas. It's a really efficient tutor and/or sidekick who can either explain topics in more depth, find better sources, or help me explore new theories. I was thinking beyond just generating code, which is incredibly useful but only mildly interesting.
Well, the research is sometimes 10x quicker with AI assistant. But not always. Building phase is maybe 20-100% quicker for me at least, depending on the complexity of the project. Green field without 15 years of legacy that is never allowed to break is many times faster, always has been.
It really really really depends on how you are using it and what you are using it for.
I can get LLMs to write most CSS I need by treating it like a slot machine and pulling the handle till it spits out what I need, this doesnt cause me to learn CSS at all.
I find it a lot more useful to dive into bugs involving multiple layers and versions of 3rd party dependencies. Deep issues where when I see the answer I completely understand what it did to find it and what the problem was (so in essence I wouldn't of learned anything diving deep into the issue), but it was able to do so in a much more efficient fashion than me referencing code across multiple commits on github, docs, etc...
This allows me to focus my attention on important learning endeavors, things I actually want to learn and are not forced to simply because a vendor was sloppy and introduced a bug in v3.4.1.3.
LLMS excel when you can give them a lot of relevant context and they behave like an intelligent search function.
Indeed, many if not most bugs are intellectually dull. They're just lodged within a layered morass of cruft and require a lot of effort to unearth. It is rarely intellectually stimulating, and when it is as a matter of methodology, it is often uninteresting as a matter of acquired knowledge.
The real fun of programming is when it becomes a vector for modeling something, communicating that model to others, and talking about that model with others. That is what programming is, modeling. There's a domain you're operating within. Programming is a language you use to talk about part of it. It's annoying when a distracting and unessential detail derails this conversation.
Pure vibe coding is lazy, but I see no problem with AI assistants. They're not a difference in kind, but of degree. No one argues that we should throw away type checking, because it reduces the cognitive load needed to infer the types of expressions in dynamic languages in your head. The reduction in wasteful cognitive load is precisely the point.
Quoting Aristotle's Politics, "all paid employments [..] absorb and degrade the mind". There's a scale, arguably. There are intellectual activities that are more worthy and better elevate the mind, and there are those that absorb its attention, mold it according to base concerns, drag it into triviality, and take time away away from higher pursuits.
I agree with your definition of programming (and I’ve been saying the same thing here), but
> It's annoying when a distracting and unessential detail derails this conversation
there is no such details.
The model (the program) and the simulation (the process) are intrinsically linked as the latter is what gives the former its semantic. The simulation apparatus may be noisy (when it’s own model blends into our own), but corrective and transformative models exists (abstraction).
> No one argues that we should throw away type checking,…
That’s not a good comparison. Type checking helps with cognitive load in verifying correctness, but it does increase it, when you’re not sure of the final shape of the solution. It’s a bit like Pen vs Pencil in drawing. Pen is more durable and cleaner, while Pencil feels more adventurous.
As long as you can pattern match to get a solution, LLM can help you, but that does requires having encountered the pattern before to describe it. It can remove tediousness, but any creative usage is problematic as it has no restraints.
Qua formal system, yes, but this is a pedantic point as the aim - the what - of a system is more important than the how. This distinction makes the distinction between domain-relevant features and implementation details more conspicuous. If I wish to predict the relative positions of the objects of our solar system, then in relation to that end and that domain concern, it matters not whether the underlying model assumes a geocentric or heliocentric stance in its model (that tacitly is the deeper value of Copernicus's work; he didn't vindicate heliocentrism, he showed that a heliocentric model is just as explanatory and preserves appearances equally well, and I would say that this mathematical and even philosophical stance toward scientific modeling is the real Copernican revolution, not all the later pamphleteer mythology).
Of course, in relation to other ends and contexts, what were implementation details in one case become the domain in the other. If you are, say, aiming for model simplicity, then you might prefer heliocentrism over geocentrism with all its baroque explanatory or predictive devices.
The underlying implementation is, from a design point-of-view, virtually within the composite. The implementation model is not of equal rank and importance as the domain model, even if the former constrains the latter. (It's also why we talk about rabbit-holing; we can get distracted from our domain-specific aim, but distraction presupposes a distinction between domain-specific aim and something that isn't.) When woodworking, we aren't talking about quantum mechanical phenomena in the wood, because while you cannot separate the wood from the quantum mechanical phenomena as a factual matter - distinction is not separation - the quantum is virtual, not actual with respect to the wood, and it is irrelevant within the domain concerning the woodworker.
So, if there is a bug in a library, that is, in some sense, a distraction from our domain. LLMs can help keep us on task, because our abstractions don't care how they're implemented as long as they work and work the way we want. This can actually encourage clearer thinking. Category mistakes occur in part because of a failure to maintain clear domain distinctions.
> That’s not a good comparison. Type checking [...]
It reduces cognitive load vis-a-vis understanding code. When I want to understand a function in a dynamic language, I often have to drill down into composing functions, or look at callers, e.g., in test cases to build up a bunch of constraints in my mind about what the domain and codomain is. (This can become increasingly difficult when the dynamic language has some form of generics, because if you care about the concrete type/class in some case, you need even more information.)
This cognitive load distracts us from the domain. The domain is effectively blurred without types. Usually, modeling something using types first actually liberates us, because it encourages clearer thinking upfront about the what instead of jumping right into how. (I don't pretend that types never increase certain kinds of burdens, at least in the short term, but I am talking about a specific affordance. In any case, LLMs play very nicely with statically-typed languages, and so this actually reduces one of the argued benefits of dynamic languages as ostensibly better at prototyping.)
> As long as you can pattern match to get a solution [...]
Indeed, and that's the point. LLMs work so well precisely, because our abstractions suck. We have lot of boilerplate and repetitive plumbing that is time-consuming and tedious and pulls us away from the domain. Years of programming research and programming practice has not resolved this problem, which suggests that such abstractions are either impractical or unattainable. (The problem is related to the philosophical question whether you can formalize all of reality, which you cannot, and certainly not under one formal system.)
I don't claim that LLMs don't have drawbacks or tradeoffs, or require new methodologies to operate. My stance is a moderate one.
> Yes but that’s why you ask it to teach you what it just did.
Are you really going to do that though? The whole point of using AI for coding is to crank shit out as fast as possible. If you’re gonna stop and try to “learn” everything, why not take that approach to begin with? You’re fooling yourself if you think “ok, give me the answer first then teach me” is the same as learning and being able to figure out the answer yourself.
I would consider this a benefit. I've been a professional for 10 years and have successfully avoided CSS for all of it. Now I can do even more things and still successfully avoid it.
This isn’t necessarily a bad thing. I know a little css and have zero desire or motivation to know more; the things I’d like done that need css just wouldn’t have been done without LLMs.
I find it intellectually exhausting to describe to a machine what I want, when I could build something better in the same amount of time, and it isn't for lack of understanding how the LLM works.
It takes a lot of cajoling to get an LLM to produce a result I want to use. It takes no cajoling for me to do it myself.
The only time "AI" helps is in domains that I am unfamiliar with, and even then it's more miss than hit.
> I find it intellectually exhausting to describe to a machine what I want, when I could build something better in the same amount of time, and it isn't for lack of understanding how the LLM works.
I don’t even bother. Most of my use cases have been when I’m sure I’ve done the same type of work before (tests, crud query,…). I describe the structure of the code and let it replicate the pattern.
For any fundamental alteration, I bring out my vim/emacs-fu. But after a while, you start to have good abstractions, and you spend your time more on thinking than on coding (most solutions are a few lines of codes).
It is better than doomscrolling on Instagram for hours like the new generations. At least the brain is active, creating ideas or reading some text nonstop to keep itself active.
Are you sure that is not the illusion of learning? If you don't know the domains, how can you know how much you now know? Especially consider that these models are all Dunning Kruger-inducing machines.
Agree on that too. And I use these as tools. I don't think I'm missing out on anything if I use this drill press to put a hole through an inch of steel instead of trying to spend a day doing it wobbly with a hand-drill.
It's not "wildly" different behavior based on the thing it's pointing to. In all 3 cases, the command is pointed at a commit and the behavior is the same. Once you know that branches/HEAD are just named pointers to commits, then it becomes obvious you are always just working on commits and branches/ids/HEAD etc are just ways of referencing them.
But branches are not just named pointers to a commit. If they were, then checking out the pointer would be the same as checking out the commit itself. But I can check out a commit and I can check out a branch and depending on which I've done, I'm in two different states.
Either I'm in branch state, where making a commit bumps the branch pointer and means the commit will be visible in the default log output, or I'm in "detached head" mode, and making a commit will just create a new commit somewhere that by default is hidden into I learn what a reflog is. And the kicker is: these two states look completely identical - I can have exactly the same files in my repository, and exactly the same parent commit checked out, but the hidden mode changes how git will respond to my commands.
In fairness, none of this is so difficult that you can't eventually figure it out and learn it. But it's not intuitive. This is the sort of weirdness that junior developers stumble over regularly where they accidentally do the wrong kind of checkout, make a bunch of changes, and then suddenly seem to have lost all their work.
This is one of the ways that I think the JJ model is so much clearer. You always checkout a commit. Any argument you pass to `jj new` will get resolved to a commit and that commit will be checked out. The disadvantage is that you need to manually bump the branch pointer, but the advantage is that you don't necessarily need branch pointers unless you want to share a particular branch with other people, or give it a certain name. Creating new commits on anonymous branches is perfectly normal and you'll never struggle to find commits by accidentally checking out the wrong thing.
No they don't. As you noted, one state is "detached head" and any competently set up shell PS1 will tell you that, or that you're on a branch by displaying the name of the branch vs the commit.
> Creating new commits on anonymous branches is perfectly normal
Sorry, that that's an example of more intuitive behavior on jj's partc, you've lost me. I've done that intentionally with git, but I know what I'm doing in that case. For someone new to version control, committing to an unnamed branch doesn't seem like a desired operation no matter which system you're using. What's wrong with requiring branches to be named?
> For someone new to version control, committing to an unnamed branch doesn't seem like a desired operation no matter which system you're using.
We have data on this! I can't cite anything public, but companies like Meta have to train people who are used to git to use tools like sapling, which does not require named branches. In my understanding, at first, people tend to name their branches, but because they don't have to, they quickly end up moving towards not naming.
> What's wrong with requiring branches to be named?
Because it's not necessary. It's an extra step that doesn't bring any real benefits, so why bother?
Now, in some cases, a name is useful. For example, knowing which branch is trunk. But for normal development and submitting changes? It's just extra work to name the branch, and it's going to go away anyway.
Fascinating. The benefit it brings is you can map the branch to its name. Of the, say, 10 branches you've got checked out, how do you know which branch maps to jira-123 and which one maps to jira-234, or if you're using names, which anonymous branch maps to addFeatureA or fixBugB?
More to the point though, what tooling is there on top of raw jj/git? Specifically, there's a jira cli (well, multiple) as well as a gh cli for github as well as gitlab has one as well. When you call the script that submits the branch to jira/github/gitlab, how does it get the ticket name to submit the code to the system under? Hopefully no one's actually opening up jira/github/gitlab by hand and having to click a bunch of buttons! So I'll be totally transparent about my bias here in that my tooling relies on the branch being named jira-123 so it submits it to jira and github from the command line and uses the branch name as part of the automated PR creation and jira ticket modification.
> Of the, say, 10 branches you've got checked out, how do you know which branch maps to jira-123 and which one maps to jira-234, or if you're using names, which anonymous branch maps to addFeatureA or fixBugB?
The descriptions of the changes. I shared some jj log output in another comment, here it is with more realistic messages, taken from a project of mine:
@ vvxvznow
│ (empty) (no description set)
│ ○ uuowqquz
├─╯ Fix compiler panic in error rendering for anonymous struct methods (rue-fwi9)
│ ○ uvlpytpm
├─╯ Stabilize anonymous struct methods feature
◆ lwywpyls trunk
│ Fix array return type unification in type inference
That (rue-fwi9) is the equivalent of jira-123, if I super care about it being obvious, I might put it in the message. But also, I might not, as you can see with the other two. You could also pass flags to see more verbose output, if the first line isn't clear enough, but in general, the convention for git as well is to have that short summary that explains your change, so if it's confusing, you probably need to do better on that.
> Specifically, there's a jira cli (well, multiple) as well as a gh cli for github as well as gitlab has one as well.
These systems do require branches in order to open a pull request. In these cases, I use `jj git push -c <change id>`, which will create a branch name for me, and push it up. This is configured to produce a branch name like steveklabnik/push-mrzwmwmvkowx for a change with the id mrzwmwmv, and ultimately, it's still easier to name locally with m or mr depending on if the prefix is ambiguous. That said, from there I do usually just click the button and then "open pull request" on GitHub, but like, all of these tools (gh is the only one I've used, but I can't imagine that the others do not work, since ultimately, it's a git repo) just work if you want to use them.
Other systems do not even require a branch to submit, and so you don't even need to do this. I would say "submit mr" and it would return me the URL for the created change request. Gerrit does this on top of plain old git.
> how does it get the ticket name to submit the code to the system under?
I haven't worked with Jira in a long time, but with GitHub, if I make a change that fixes issue 5, I put "Fixes #5" in my description, and when the PR is created, it updates ticket #5 to link the PR to that change automatically, no other process needed.
Right, this is a good point: you can if you want to, or if you're working with a system that requires them.
Just in practice, anonymous branches end up feeling very natural, especially during development, and especially if your code review tooling doesn't require names.
They look identical to people who don't know what to look for, and who don't realise that these two states are different, which is the key thing. You can also distinguish them by running `git status`, but that's kind of the point: there's some magic state living in .git/ that changes how a bunch of commands you run work, and you need to understand how that state works in order to correctly use git. Why not just remove that state entirely, and make all checkouts behave identically to each other, the only difference being which files are present in the filesystem, and what the parent commit was?
What's wrong with unnamed branches? I mean, in git the main issue is that they're not surfaced very clearly (although they exist). But if you can design an interface where unnamed branches are the default, where they're always visible, and where you can clearly see what they're doing, what's wrong with avoiding naming your branches until you really need to?
I think this is the key thing that makes jj so exciting to me: it's consistently a simpler mental model. You don't need to understand the different states a checkout can be in, because there aren't any - a checkout is a checkout is a checkout. You don't need to have a separate concept of a branch, because branches are just chains of commits, and the default jj log commands is very good at showing chains of commits.
or
fragmede@laptop:(abcdef)~/projects/project-foo$
Depending on if abranch is checked out, or abcdef which may be HEAD of abranch is checked out.
If you're having to run `git status` by hand to figure out which of the two states you're in, something's gone wrong. (That something being your PS1 config.) If people are having trouble with that, I can see why switching to a system that doesn't have that problem, it just that it doesn't seem like it should even be problem to begin with. (It's not that it's not useful to have unnamed branches and to commit to them, just that it's not a intro-to-git level skill. Throwing people into the deep end of the git pool and being surprised when some people sink, isn't a good recipe for getting people to like using git.)
> What's wrong with unnamed branches?
As you point out, those commits kinda just go into the ether, and must be dug out via reflog, so operationally, why would you do that to yourself. Separate from that though, do you "cd" into the project directory, and then just randomly start writing code, or is there some idea of what you're working on. Either a (Jira) ticket name/number, or at least some idea of the bug or feature you wanna work on. Or am I crazy (which I am open to the possibilty) and that people do just "cd" into some code and just start writing stuff?
VCS aside, nothing worse than opening Google docs/a document folder and seeing a list of 50 "Untitled document" files an my habit of naming branches comes from that. Even though I'm capable of digging random commits out of reflog, if all of those commits are on unnamed branches, and have helpful commit messages like "wip" or "poop", figuring out the right commit is gonna be an exercise in frustration.
As long as you've got something that works for you though, to each their own. I've been using too long for me to change.
The only thing that changed in the two things you wrote was `ranch` -> `cdef`. Every other part of that PS1 output was the same.
Now put yourself in the shoes of a git novice and ask yourself if you'd always notice the difference. At least from my experience, they often don't, especially if they're concentrating on something else, it if they're using an IDE and the visual information about which branch/commit is checked out.
I don't think you're crazy, I think you're just too used to this sort of stuff to remember what it was like to still be learning git. When I say people make these sorts of mistakes, I'm thinking about real colleagues of mine who have made exactly these mistakes and then panicked that commits suddenly had disappeared.
Similarly, I think to you, unnamed branches feel like something complicated because in git that are. Git makes it very easy for commits to seemingly disappear into the ether, even though they are still there. But in jj, they don't disappear - they remain very visible, and the log UI shows them in a way that makes it clear where they come from. The default log UI is something like git's --graph output, which means you see how the different commits interact with each other. I really recommend having a look at the output of `jj log`, because I think then it'll be a lot clearer what I mean when I say that it's not hard to figure out what the right commit is.
Sometimes it seems to me that's only in SWE we allow people to proceed in the workplace without any training. There's enough learning material that people should take a week or something to practice git and not be git novice anymore.
Or you make tools that are easier to use, so that you can spend that week learning something more useful than the finicky details of branch vs detached head checkouts.
Don't get me wrong, git has some accidental complexity (as will any tool introduced, including what I am seeing with jj). But a lot of it is just incidental complexity. It doesn't matter how much lipstick you put on it, at the end of the day some concepts need to be learned.
Did you mean inherent complexity instead of incidental complexity?
I think the inherently complex things in git are (1) the content-accessible object store, snapshots, plus the merkel tree approach to keeping track of commits and parenthood, (2) merges, rebases, and resolving conflicts between two different changes with a common ancestor, (3) possibly syncing commits between different remotes, although I think Git's approach adds accidental complexity to the problem as well.
Everything else is a question of the user interface: how you choose to show a commit, how you choose to update the project files, how you choose to let people create new commits, etc. And I think the Git CLI is a poor user interface in a lot of places. There are a lot of features which are really powerful but difficult to use, whereas actually they could be just as powerful but far more intuitive to use.
In fairness, this is no slight to the Git developers - they are improving a lot of that interface all of the time. And finding a simpler interface is often a lot more hard work than finding the complicated interface, and I don't think I would have figured out how to create something like jj until I'd seen it before.
I think you need to setup something like magit, tig, and maybe lazy git, to truly see the power of git. Most people don't do version control other than snapshotting things every once in a while. They might as well use git inside cron.
A patch is an idea to take the code from a state to another state. It contains both the mechanical work, the intent, and extra metadata. It's essential when doing distributed development work over a single code base. A git repo is a node and it lets you accept and produce new message to the other nodes.
If you care about the state of the canonical repo, you want every step to be able to compile/build/be verified. So that means accepting good patches from everyone else.
But the work of producing new patches can be messy. But you still need to track each steps, branch off to do experiments, catchup with new updates to the foundational model of the code,...
The design of how git store information makes all those operations simple while giving you the maximum control over them. But there's one mechanism that is kinda the bane of every novice: diffing and patching. Because git doesn't store the file deltas. It stores the changed files. Diffing is the interface for inspecting the changes and patching is how those changes are propagated to files.
The default diff mechanism relies heavily on lines. Which suits most programming languages as a line is often the unit of intent. Conflict occurs when git detect that two diffs is trying to alter the same section of the files. It's actually a solution mechanism instead of a problem as most novices see it.
But I don't blame them as a lot of novice don't have experience with reading diff files or use the patch tool to apply such changes. The tree of commits and object store is more easily explained (although it rarely get explained). But a lot of fellows I met are genuinely terrified of resolving conflicts, because they can't read diff files.
I genuinely think that git is an awesome tool. But you need to get familiar with some concepts like: What a commit is, what a branch is actually, why HEAD is important,... The operations like fetch, pull, push, rebase, cherry-pick, commit, checkout,... become way more obvious.
I'd add jj to that list, tbh. It simplifies a lot of stuff, but in doing so it exposes a lot of those core ideas. That's where I got my list of essential complexity, really - the stuff that comes to the fore when you start using jj.
Is the difference between these 3 really that subtle? How do you miss that the line lengths are different and that one of them is a pile of letters and the other is a word? I'm not trying to die on some "git is easy to use" hill because it isn't. Just that the difference between unnamed branches and named branches isn't this hidden undiscoverable thing. I don't have access to this dataset of Mr Klabnik's, but apparently it is.
I don't know how much it matters in AI-codepocalypse because I'll be honest, I haven't used git manually in days. AI writes my commit messages and deals with that shit now. (Claude ends a session with "Want me to push it?" and I just reply "yes".
> Similarly, I think to you, unnamed branches feel like something complicated because in git they are.
It's not that working with unnamed branches in git seems complicated, it's that it seems opposite to how I, and by extension, other people work. Now, obviously that assumption of mine doesn't hold true, otherwise we wouldn't be having this discussion, but going back to my Google docs example, staring at a page of documents called Untitled document isn't helpful, so in my mind, there's just a bit of digital hygiene that's necessary under any system.
> I really recommend having a look at the output of `jj log`, because I think then it'll be a lot clearer what I mean when I say that it's not hard to figure out what the right commit is.
You tell me which commit I want from this `jj log` output:
The effort to label those with `jj describe` what "nrqwxvzl" is vs "nkuswmkt" could just as well be put into using named branches.
Again, I'm not trying to die on a "git is easy to use" hill, because it isn't. My point was that "> these two states look completely identical" isn't true if you setup PS1 to tell you what state you're in.
jj gets a lot of things right, there's no panicking that work got lost. That is a big deal! The emotion toll that the possibility of that happening with git causes on new users is hard to understate. It's hard to not be scared of git after you've lost hours of work after running the wrong command.
I didn't raise $17m to build what comes after git, although I've thought a lot about that problem. Improvements in that area are welcome, and the easier it is for people to work with stacked change sets and branches, globally, can only be a good thing. I can't make everyone else get as good at git as I am (or better!), so I welcome better tooling.
I don't understand your example. Why haven't you added commit messages? Would you do that with git? In what situation are you creating different branches like that and not using either `jj commit` or `jj describe`?
> any competently set up shell PS1 will tell you that
I certainly hope your shell is not running `git` commands automatically for you. If so, that is a RCE vulnerability since you could extract a tarball/zip that you don't expect to be a git repository but it contains a `.git` folder with a `fsmonitor` configured to execute a malicious script: https://github.com/califio/publications/blob/main/MADBugs/vi...
Might want to let git know. It's been a part of the git source code since 2006. If there were an RCE vulnerability from using __git_ps1, one would hope it would have been found by now!
I was able to reproduce it using that script in my PS1 when `GIT_PS1_SHOWUNTRACKEDFILES=1` which triggers a call to `git ls-files`. Without that, it seems to be just calling `git rev-parse` which does not execute fsmonitor.
I was also able to reproduce it with `GIT_PS1_SHOWDIRTYSTATE=1` which invokes `git diff`.
If you don't provide it a <tree-ish> it reads from the index (staged files). So you're right its not really pointed anywhere, since the index isn't a ref.
That's my overall point: the argument itself (with respect to the current state of the repo) is what determines the behavior. I don't think this is anywhere close to as intuitive as commands that only ever accept one "type" of argument (and erroring if it's different).
I stand corrected by this one scenario, but I’ve been using git for over a decade and never found that useful. Just don’t use checkout on a file path, there is no need.
I find this kind of advice to be a more scathing indictment of an interface than a critic could ever muster: asking users to forego available functionality so that some sense of order can be imposed.
That goes in the same bucket as rebase. Until you know what it does, you'll be fine avoiding it.
Since people are sharing their experiences and my recent one is relevant to edit, I'll go:
Working on a feature recently, I ended up making 3 changes ("commits") on top of each other and hopping between them via jj edit.
The first change wasn't feature specific, it was extending the base project in preparation.
The second change just added a doc describing all the changes needed for the feature.
The third change removed the doc as parts were implemented, bit by bit.
As I progressed on the third change & found stuff I'd missed at the start of this process, I jumped back to edit the first change (maybe I had a bug in that base project extension) and the second change (oh hey, I found something else that needed to be done for the feature).
It sounds crazy compared to a git workflow, but at the end of the process I have 3 changes, all tested & working. If I was doing this with git, I'd have to rebase/squash to get the final changes into a neat clear history.
I suggested that since you seemed really concerned about editing the commit that you just told it to edit. Use 'edit' all you want if your goal is to edit commits, otherwise 'new' does what it seems like you're expecting...
edit is useful and there are good reasons to use it, 'never use edit' is like 'never use goto' i.e. false - but if you're just starting out, jj new/jj squash is the way to go indeed.
(my particular favorite reasons to use jj edit are git-native tools which expect to work with uncommitted files e.g. autoformatters, linters, etc. which have been scripted in CI/dev workflows such that they cannot accept a list of files as params)
"Just don't accidentally do things wrong" is also the way to avoid null pointer errors, type mismatches in dynamically typed languages, UB in C/C++. It works, until it doesn't, and in practice that happens pretty quickly. Personally, I like things that have proper safety checks.
Except it's not an unrecoverable error. If you do it all it does is add that file to the working index. No commits are made and no harm is done. So no, I do not feel it's the same as a null pointer exception or type mismatch.
> If you do it all it does is add that file to the working index.
No, that's not at all what it's doing!
git init
touch foo.txt
git commit -m 'empty foo.txt'
echo something >> foo.txt
git diff --stat # Shows one line added to foo.txt
git checkout foo.xt
git diff --stat # empty output; no changes!
It removes changes that are not yet checked in. You can only get them back by going into the reflog (which is pretty much identical to the situation described with `jj edit` at the beginning of this thread; `jj op log` will let you get them back fine).
edit: Actually, I was wrong; the changes will NOT be in the reflog because they were never checked in. It's fully destructive; you've lost the changes and don't have any way of getting them back through git. This is strictly worse than anything possible with `jj edit`, and even when making this point I didn't realize how bad it was, and clearly neither did anyone defending it.
The fact that there have already been two instances of defending git's behavior without even understanding what it's doing with this command is exactly my point. It's not your fault; the command is unintuitive, and that's my entire point. How many times should it take for people to try to explain what's happening incorrectly before we accept this?
It's a useful thing to be able to do! It just fundamentally shouldn't be under one command. To its credit, git did add `switch` (with `-c` for creating a new branch and `-d` for specifying detached HEAD), but after two decades I can't imagine they'll ever get rid of checkout entirely because it was so fundamental for so long, and as long as its there, it's a loaded footgun with the safety off.
If you don't run checkout on file paths, how do you undo changes to specific files that you haven't committed yet? Like you've edited but not committed <foo>, <bar>, and <baz>. You realize your edits to <bar> are a mistake. I'd just run `git checkout <bar>` to revert those changes, what do you do?
It is also really useful when you realize you want <bar> to be the version from a commit two weeks ago. I guess you could always switch to the branch 2 weeks ago, copy the file to /tmp/, switch back, and copy the file into place, but `git checkout c23a99b -- <bar>` is so quick and easy. Or does this example not fall under the "dont run checkout on a path" since it is taking a treeish first before the path?
That is entirely dependent on your diet as a child. I know children that love bitter or sour/fermented foods. Not to mention they dislike things that are overly sweet.
I wouldn't be surprised if all tastes are essentially "acquired".
This is not the only model. I assure you exploits are being found and taken advantage of without it, possibly even ones that this model is not even capable of detecting.
Sounds like people here are advocating a return to security through obscurity which is kind of ironic.
Are you arguing that eventually a competitor will emerge that does support OpenClaw with a subscription model? Wouldn’t that just be more expensive for the exact same reason Anthropic is banning it?
OpenAI have literally gone out of their way to explicitly support this sort of thing. As they did with OpenCode.
Honestly, this just looks like what Dylan of SemiAnalysis suggested on Dwarkesh – that they've massively under-provisioned capacity / under-spent on infrastructure.
That would honestly be a comforting answer if true, because I would gladly take 'we can't afford to do this right now' over 'we are self-preferencing, and the FTC should really take a look at us, even if we're technically not a monopoly right now, since we're the only strongly-instruction-following model in town and we clearly know it'.
> we are self-preferencing, and the FTC should really take a look at us, even if we're technically not a monopoly right now
Tell me you have zero clue what a monopoly is or what the law is, without telling me.
Monopoly law relies on broad categories, not narrow ones. You can’t call Microsoft a monopoly because they are the only company that makes Windows. You can’t call Amazon a monopoly because they are the only company that makes AmazonBasics. You can’t call Anthropic a monopoly because their product is 20% better for your use case, otherwise by definition no company has any incentive to do a good job at anything.
Somehow this was coming up a few years ago where people kept saying that Apple could face antitrust because they were the only company who made iOS and controlled the App Store. Given that android exists, and has roughly equal market share, that didn’t make much sense to me, but I kept seeing it being discussed.
> Tell me you have zero clue what a monopoly is or what the law is, without telling me.
Monopoly law is subject to reinterpretation over time and anybody who has studied the history of it knows this. The only people argue for "strict" interpretations of current monopoly law are those who currently benefit from the status quo.
> Monopoly law relies on broad categories, not narrow ones.
And this is currently a gigantic problem. Because of relying on broad categories to define "monopoly", every single supply chain has been allowed to collapse into a small handful of suppliers who have no downstream capacity thanks to Always Late Inventory(tm). This prevents businesses from mounting effective competition since their upstream suppliers have no ability to support such activities thanks to over-optimization.
To be effective on the modern incarnation of businesses, monopoly law needs to bust every single consolidated narrow vertical over and over and over until they have enough downstream capacity to support competition again.
Oh, give me a break. I know the law around this incredibly well. Reasonable people can disagree about whether the law is appropriate. The whole point of laws is that they should match intent – and as for '20%': "tell me you don't understand how a small quantitative gap can result in a step change in capability."
> Oh, give me a break. I know the law around this incredibly well.
Then don’t make BS up like implying Anthropic is a monopolist for the crime of competence.
> tell me you don't understand how a small quantitative gap can result in a step change in capability
The law does not give a darn about this. Being a good competitive option does not make you a league of your own. If I invent a new flavor of shake, the Emerald Slide, am I a monopolist in shakes because I’m the only one selling Emerald Slides? If you go and then start a local business reselling shakes and I’m your only supplier, am I a monopolist then? Absolutely not.
You do realize that I called out in my post they are absolutely not a monopoly by the law, right? I know all-too-well what the definition is.
We have a similar situation in mobile where Apple may not be considered a monopoly, but people have walked around for a decade with a supercomputer in their pocket that is wildly underused.
Things have gotten faster; things are different than they were decades ago when a lot of this was devised.
The reality of the matter is that some of us just want to see innovation actually happen apace, and not see 5, 10, or 30 years of slowdown while we litigate whether or not such a company is holding all the cards, while everyone is collectively waiting at the spigot for a company to get its shit together because we're not allowed to fix the situation.
For what it's worth, I'm hopeful that the other model providers will catch up and put us in a situation where this conversation is irrelevant.
What I'm afraid of is a situation where we see continued divergence, and we end up with another Apple situation.
> “we are self-preferencing, and the FTC should really take a look at us, even if we're technically not a monopoly right now”
That is not calling out that they are “absolutely not a monopoly by the law” in any way, shape, or form. You’re framing it as though they aren’t by a technicality, when they aren’t anywhere near discussion by even the most extreme of legal theories. You won’t find Lina Khan or Margarethe Vestager, both ousted for going too far, complaining about Anthropic.
> “We have a similar situation in mobile where Apple may not be considered a monopoly, but people have walked around for a decade with a supercomputer in their pocket that is wildly underused.”
In that we can’t run a Torrent client to download illegally redistributed media 99% of the time? Otherwise, in what way, are they underused? For the degrees of public addiction, a more underutilized phone would be a social benefit.
Let me back up what you're saying. They absolutely are not a monopoly today by any definition, by any stretch, in any conceivable way.
I'm looking forward. Things are moving very quickly. As I said above, I'm afraid of us diverging into another Apple situation in the future. If I suggest that they should be looked at and thought about, it's not for today, it's for tomorrow. If divergence continues. Because as with everything in AI, it might hit us a lot faster than people expect. Hell, given their approach to morality, I suspect that Anthropic folks have already thought deeply about these sorts of concerns. That's why it's actually a lot more in character for them to be doing this not due to self-preferencing, but due to unaffordability, which - if you look at my first post - is what I said seems to be happening.
Suffice to say that I have a graveyard of things that I think phones could have been, where unfortunately we've ended up with these - as you say - addicting consumerist messes.
Gonna stop here so I don't flood the thread. We're getting very off topic.
It's a good way to win market share and build goodwill, but one has to wonder whether this class of usage is marginally profitable for them (or anyone) and how sustainable their lenient policies will be for them long term.
The real threat that Anthropic sees as real competitors in the long term, are the AI labs building open weight models, especially the AI labs in China.
I agree, eventually the open models will be good enough and we can pay for our own infra and cut out the middle man. Also, the smaller frontier are nearly as good today and I expect the mega models will be used primarily for distillation
reply