Hacker Newsnew | past | comments | ask | show | jobs | submitlogin
Asqi: A codebase explorer designed to help navigate and understand Git projects (asqi.io)
101 points by guitarsteve on May 30, 2024 | hide | past | favorite | 38 comments


Fireship got hacked. Ticketmaster had user info stolen. et al, so when I see:

> I log barely enough to determine whether the server has crashed.

> We do not collect nor track...

I'm 50% sold by these principles alone.

It's 2024 and not being a data creep is a product feature now.

Thank you.


You're very welcome. I wanted to build a product I would use, and being hands-off about customer data is a big part of that. (I was trying to use another code search tool and bailed because it wanted me to sign into Github just to use it locally.) So Asqi will always be designed with that sensibility, including commercial versions which also will never phone home -- licensing will be airgap-compatible.


Fireship or firebase?


Firebase. Thanks. Got it swapped for the YouTube channel.


I like the speed and compactness of the UI.

Hopefully constructive feedback.

1. That message about upcoming feature obscures the code and is actually a big div taking the whole right side, from top to bottom, which blocks events like scrolling with mouse wheel. It's white so it looks like part of code but blocks scrolling of code.

2. those circular things are a gimmick in my mind. And acting on hover is confusing: I move the mouse and things flash wildly.

Give me a clear option to permanently hide the circular thingy.

Only act on click, not mouse over.

3. When I clicked on an enum definition (e.g. in postgres parser) I expected a way to see all places that use that enum. It's not possible or I'm missing something.

4. The "search everywhere" dialog is confusing. Again, a big circular thingy, invisible cursor so I don't even know I can type something and I don't know what I'm searching there. File names? I expect search to be full text search of all files.

5. I was confused by `C-u`. Now I get that it's `Ctrl-u` but make it more obvious . At least in help use the full `Ctrl-u` and add tooltips with full version.

6. The color of tabs is the inverse of what I expect based on pretty much all other software I use. A current tab should have the same color as the panel, so that it looks like it's part of it. Since panel is white, selected tab (e.g. History vs. Tree) should also be white. It's black. Or find some other way to make it clear which tab is selected.


> I was confused by `C-u`.

That's the old fashioned, traditional way to represent shortcuts.

Example:

https://courses.cs.washington.edu/courses/cse351/16wi/sectio...


Thanks so much for writing this up, it's great! Let me get some coffee and I'll share some thoughts about where we are and where it's going.


This is absolutely constructive feedback, thank you again for writing it all up. I'll go through point by point and share my thoughts about each one.

Re speed and compactness, thank you! These are two things I really value in UIs, and I optimized Asqi pretty relentlessly to make it fast. It's good to hear that it's appreciated and I'm glad you said something.

1. The "feature coming soon" is awful and embarrassing. It exists because I wanted to make it clear that Asqi has a strong emphasis on history -- in fact, that's fundamentally what it's about -- even though big parts of that feature-space aren't implemented yet. But it was so painful to ship that way; I hate that div so much for blocking my mouse. ...so I'm sorry to you and everyone else that you have to suffer through the existence of that panel.

2a. Circular things, which we internally call bagels, are 100% a gimmick. Ultimately their job is just to look at code top-down, and there are probably better ways to do it although I don't know of any yet. But the problem is that I can be bought (at least in UI terms), and I realized that I really liked the way code looks in concentric circles. So I had these two conflicting thoughts: "this is cool and visually anchors the product", and "this is stupid and no serious person would find it valuable."

I tried rendering diffs in bagel form, which you can see if you shift-click other branches in the history tab to get this URL: https://demo.dev.asqi.io/#fast-libgit2::main,#6818,#6819,#68...::::. So cool, we have multiway diffs rendered in tree form, and now when you hover the elements you see which branches modified each blob. But it still feels like a gimmick because I can't really conclude that it's better than a properly-executed tree view. I don't know how to properly execute a tree view enough to make me dislike the bagel holistically, but if I ever do then the bagel is out. There's plenty to dislike about it.

2b. Hover-actions are central to Asqi's design and I love them, but I'm a sloppy-focus person and that's definitely a minority preference. The flashing is awful and the epilepsy warning was comically embarrassing to have to include. I think a toggle is definitely worthwhile so people don't suffer through my ergonomic biases.

I spent a bunch of time wringing as much see-things leverage out of each screen as I could, except for the despised "feature coming soon" div discussed above, and even did some things like if you hover over a repo-local link in a markdown, scrolling on that link scrolls the link's destination so you can peek into the contents without moving your UI frame of reference. If the user had to click on stuff, they'd have a deeper navigation history and more backtracking.

Having said all that, your perspective is also entirely valid. There's a point where your preferences may diverge from Asqi's design enough that Asqi isn't for you, but I don't think it's here. Asqi needs to meet you on this one by at least providing an option.

3. We don't yet have go-to-references, and perhaps never will. We don't actually have a precise definition/reference linkage for the codebase at all because I don't know how to represent it efficiently across multiple commits. Sourcegraph does it for one revision but not for all to my knowledge (I think if you explore past commits and jump to definition, it jumps into the present, for example). In the first months of Asqi I was so bent on solving this problem that I was designing type-system compilers whose sole purpose was to emit bytecode that implemented the jump-to-definition program across different blob/tree revisions. Then I realized Asqi isn't really about that and I'm not sure that's a product. That said, I also feel the lack of go-to-references and I've been thinking about whether it's implementable. I want it to be because it's a good feature.

4. The Ctrl+K dialog is half-baked and awful. It barely works, in fact. It's supposed to autocomplete words as you type, but it doesn't; instead, it alternates between autocompletions and path completions and expects you to manage focus. It is an abysmal, abhorrent piece of garbage that is second in place only to the semantic-history placeholder div in earning my ire. And like the semantic history panel, I owe you and everyone else an apology for how badly it works. It will be improved or deleted, for everyone's sake.

As for full-text search, I don't think it's going to make it in and for an interesting reason. Asqi's search backend searches for all functions that have ever existed, not just the ones in the current revision. Right now it filters down to just current ones, but "code ghosts" -- code that once existed and is now gone -- are one of the big drivers for having a semantic search feature. So Asqi's search is less about "find stuff in text" and more about "find named entities", at least for now. If the indexes don't get too big, I may also try to add the search-text use case, because I agree it would be useful and I feel the lack of that feature pretty regularly.

5. I really love this point you make, because you're 100% right and I'm kind of an asshat for not seeing it. I wanted Asqi to come across as opinionated, with some old-school sensibilities like Emacs-style key strings because they're compact and have a certain aesthetic appeal. However, Asqi's lack of regular descriptions can be read as not just anachronistic but gatekeeping, which broadly sucks and adds no value. This is another place where Asqi needs to meet the user, not expect the user to meet it. And I never would have thought of this because old-school key strings are second-nature to me. So thank you for saying something.

6. My tabs suck. I should be using a UI library, but threw them together as an early learn-React experiment and never fixed them. Eventually I'd like to get rid of pixels dedicated to things like tabs, but haven't figured out all the details yet. So you can expect crappy UI components like that to be gone soon, and please keep complaining about them (and any others) until they are.

I'm really glad you wrote all this up. It was helpful for me to go through and think about each point you made and how Asqi relates to it. I can't promise that Asqi will become a product you like, but you've given me a lot of room to think about whether it should, and I appreciate having that option. Any thoughts you have going forward are very welcome.


The demo is not working for me: https://demo.dev.asqi.io/


Hi, thanks for trying it out! The server crashed, sorry about that. I need to add a liveness check. It should be working now.

As for comments asking to install React, it's a bug on my end. Create-react-app leaves a manifest.json file in public/, which causes the prompt to appear. I've deleted it in the latest container image but haven't redeployed yet since we've got a lot of active users at the moment.

Anyway, you don't have to install anything, nor will you ever have to, in order to use Asqi.


Same, getting:

  3main.5cc1145c.js:2 TypeError: Cannot read properties of undefined (reading 'p')
    at V.rpc (main.5cc1145c.js:2:23177)
    at V.server_repos (main.5cc1145c.js:2:25611)
    at e (main.5cc1145c.js:2:93041)
Would really like to try this out


Got it working again! Sorry about that, server crash possibly from being on HN :)


Looks like it's working now - I tried out the gitlab repo. My laptops fans spun up, mousing over segments seem to freeze the UI, and I wasn't really sure what I was looking at in the first place. I think the app itself is pretty disorienting, especially compared with the simplicity of the landing page. Have you considered pre-rendering all this stuff and making the app more static? I think a significant improvement could be to change whatever is happening on hover to on click, otherwise UI elements are shifting around a lot and stalling as it synchronously retrieves elements. I really like the idea of an OSS codebase explorer though, hope you keep iterating on this project!


Yeah the locking up is a big issue right now. It happens when you first load a repo and the client populates its local IndexedDB with all the RPC data coming down, which is 10-100k insertions and causes browser slowness. I've tried a couple of strategies that run them in timed batches to avoid overwhelming the browser, but it still has trouble especially on big repos. If you know of a way to bulk-load IDB without browser issues, let me know; my next strategy is probably just going to be either to defensively trickle-load or maybe try to measure microtask wakeup times to detect event loop load for backoff. Once I get it right I'll write a blog post about it because it's an unexpectedly challenging problem.

The good news, though, is that the load delays happen only the first time: if you let it warm up once and reload later, it should be much snappier because IDB reads are much faster than IDB writes.

The hover on click idea came up in another reply and I really like it as an option you can choose. That's going to be a high priority for the next release, I'm glad you also mentioned it.

Pre-rendering is a very good idea and while I had considered it before, your comment has me thinking about a much more general use case for it. I think it might enable some very snappy UI behavior, particularly around time-scrubbing or timelapse animations. I'm really glad you said something; this might lead to something very cool.

Thanks for the kind words and thoughtful feedback!


Same demo not working for me, asks me to install a React App on the address bar in Chrome. No chance I'm installing something random.


Yeah you definitely don't need to install anything. I don't know how to deploy React apps apparently (will try to fix), but it's just a regular website and I would never ask users to expect anything else.

Update: it's because create-react-app creates manifest.json in public/, which causes Chrome to prompt you for this. I've deleted it in the latest container image and I'll redeploy once traffic dies down a bit.


Demo page is now deleted?


Nope still there, but you may have caught the server at a bad moment. Because Asqi uses the DB read/write, there's only one replica of the server and it has less than 100% uptime depending on indexing and user load.


Same here. Looks like some property of 'p' can't be read in.


I want to like this but I found the UI too confusing and didn't get anything out of the current experience.

I liked the BBS/ssh server intro and styling but you lost me at the jumpy, nested circular tree chart thingy. Maybe a boring rectangular treemap would work better? Even better if it was rendered in the terminal over ssh...


Terminal over ssh? Hahaha don't tempt me :)

I really like this idea. It's not at all what I had in mind for the product, but that's because it had never occurred to me. I'm going to give this some serious thought and see what shakes out.


Cool. You can get going in no time with Charm Wish (https://github.com/charmbracelet/wish).

Then sprinkle on magic fairy dust with TTE (https://chrisbuilds.github.io/terminaltexteffects/showroom/) so you can still have that epilepsy inducing effect :-p


Hahaha "if it doesn't cause seizures, it's not really Asqi" - well we have a brand, that's for sure :) (seriously I have got to fix this soon my god)

TTE is so freaking cool, I will hate myself if this doesn't make it in somehow. And I didn't even know it existed until now, so thank you!


I’m wondering what computer language analysis tools are necessary to make this work for another language. The OG page supplies this info

    Supported languages
    -------------------
    Asqi can provide file-level indexing for everything, 
    and it provides semantic indexing for:

    + C/C++
    + Java
    + Go
    + Rust
    + JavaScript/TypeScript
    + Python


It's actually pretty straightforward; we use tree-sitter for parsing and it takes me about 2-3 hours for each language. So I'm planning to add a lot more in the near future.

If you have any that you find especially valuable, let me know and I'll see if I can prioritize them.


With regards to your call for interesting language support, I'd add a very low-priority suggestion for documentation and specification formats. Plain text, Markdown, simple HTML paragraphs and sections. If a new paragraph or sentence is added to a spec, or a MUST becomes a MAY, it'd be neat to surface the context of the change instead of a word/line diff.

As the Semantic History is not yet available, how do you envision it being displayed at the moment? What sort of information are you currently collecting? Is this tracked across the project history? To that end, are you building Tree-Sitter grammars and queries yourself, or are you using the pre-existing grammars and building the language support into Asqi?

For context, I've got a back-burner project that maps reimplemented code (manually mapped, with annotations or structured comments) to identifiable items in an upstream codebase and git repository. When the content of an item is changed upstream, affected downstream code could be flagged for review. It's still early in the design/prototyping phase, but it feels like there's some interesting overlap with Asqi.


YES - this was very much on my mind actually. I was thinking we really need section outlining for Markdown (and for diffs etc, so like "two people want to edit this paragraph" when we have collision detection later). It didn't make it into the first cut but was and still is top of mind as I'm dogfooding it.

I have had some good ideas and some stupid ideas for semantic history, and many very mixed prototypes. The simplest option, and what I'll probably go with, is just a table of commits-modifying-this-thing. But that's not all the information; for example, a linear list of commits doesn't convey branch/merge topology well. I'm not sure how useful that information is, but I'd kinda like to see it.

The data I collect is two things: first, we can do a semantic git-diff operation in the backend; and second, we search-index the diffs so you can say "which commits modify entity X" and get a fast answer. That's what the UI will do when you focus on a function.

I use off-the-shelf TS grammars and write custom queries for them. I've got a custom abstraction in the backend that lets you query for ranges of nodes at once, which is how we jump to the top of comments above a function rather than to the function definition itself.

Your back-burner project is exactly where Asqi is headed -- and in fact, the backend for this is 100% done in Asqi but the frontend doesn't show the data yet. The idea is to determine things like, "two branches modify function X in two different ways" and even if the diffs don't collide, you get to see that there's a potential semantic conflict coming up. There's some potential opportunity to use past change data to detect when a function is sensitive to multiple editors, or when it's just a big list of calls/hooks or some such where it doesn't matter so much. So in the long term, I think of it as "how important is this potentially interesting conflict scenario" as some type of user-attention number that is priority-sorted so the user sees most-important first.

(Btw, I would personally not like to hear that my pet project was being implemented by a non-free product; the silver lining here is that Asqi will always let you analyze private repos locally if you don't need to pull them automatically -- i.e. if you have local clones -- so it's probably free for what you're doing unless you're launching a SaaS product. I may also add some type of data export API later so you can use the Asqi backend to power other frontends.)


> a table of commits-modifying-this-thing [...] a linear list of commits doesn't convey branch/merge topology well.

Agreed. Presenting both the local diff and the location in the commit graph seems like a better bet for helping people glean understanding of a change's purpose and context. I'm also thinking of using a table of per-item changes that's tied to the commit graph for topologically sorted history and reachability information. This will probably be backed by a per-commit list of item identifiers with their hashed content for easier comparison.

It sounds like your abstraction is doing a great job of representing file structure. For the most part, I'm just looking at telling users that they should look at a set of related symbols and revisions after an identifier's body has changed. The user is then responsible for performing a review and updating the "last-approved" information.

As a more concrete example, I'm expecting users to maintain their own mappings to items in the upstream sources:

  #[rawr(
      codebase = "reality",
      kind = "constant",
      identifier = "f_pi",
      path = "src/constants.h",
      revision = "123abc456",
      notes = "This probably shouldn't change, but it would be good to know if \
      the upstream team makes non-Euclidean alterations to the simulator."
  )]
  const PI: f64 = 3.14159;
If f_pi's contents have changed since revision 123, the new value can be flagged for review. In the example case, upstream's f_pi was changed to a new value. The user should be informed that PI was updated in Reality's src/constants.h@1897246. They can review the upstream change, reimplement it in the downstream codebase, and update the metadata to reflect the coordinates of the last change.

  #[rawr(
      codebase = "reality",
      kind = "constant",
      identifier = "f_pi",
      path = "src/constants.h",
      revision = "1897246",
      notes = "Required by Legal Counsel for compliance with bill #246."
  )]
  const PI: f64 = 3.2;
I'm starting to think that the best way to present the changelist is to spit out deep links into an Asqi instance. By the sounds of it, you've also got all the necessary data in the self-hosted Asqi container's /db volume. If you don't mind, I'd like to see if I can directly consume that instead of building my own Tree-Sitter integration.

(Personally, I wouldn't want to hear that my non-free product was being implemented by someone's pet project :) Thankfully, I think we're heading in different directions, leveraging and presenting the same dataset in very different ways. In this case, I'm actually thrilled that someone else is implementing the machinery required by my pet project. Now I'm closer to exploring and following the fast-moving codebases that I wanted to reimplement in the first place!)


Ruby with sorbet would be cool, and C#


For Ruby + Sorbet, it looks like Sorbet fits into Ruby syntax so we can reuse the same grammar, but you'd probably want the signatures to be considered as part of the methods. Working with the example from their website:

  sig {params(name: String).returns(Integer)}
  def main(name)
    puts "Hello, #{name}!"
    name.length
  end
I think the idea is that Asqi should treat `sig {}` sort of like a comment: prefix metadata attached to `def main`, rather than as an unrelated imperative call (whereas `attr_reader` would not have this behavior). Do you know whether Sorbet continues to work if you alias `sig` and any of its other definitions? For example, can I do this?

  def mysig(&proc)
    sig(&proc)  # or some other transformation
  end

  mysig {params(name: String).returns(Integer)}  # does this work? I hope/assume not
  def foo(name)
    name.length
  end
If the above is disallowed, then it should be easy to implement Ruby with Sorbet support built in. Otherwise I can probably do Ruby by itself, but it would be unaware of annotations attached to methods since to my knowledge there's normally no structural connection between statements that precede definitions.


> I think the idea is that Asqi should treat `sig {}` sort of like a comment: prefix metadata attached to `def main`, rather than as an unrelated imperative call (whereas `attr_reader` would not have this behavior). Do you know whether Sorbet continues to work if you alias `sig` and any of its other definitions? For example, can I do this?

No, it doesn't work if you alias


Awesome, OK I believe I can make that work then. Very glad you mentioned Sorbet because I hadn't heard of it before but it will be cool to have it ship with Ruby out of the gate.


That is very appreciated! Sorbet is shamefully underrated. While there are some weaknesses in the tool (which are fixable), the criticisms it typically gets from the community are unwarranted/unfair IMO. For example, I've heard that it makes the code too verbose. But in my experience, inserting T.cast or T.unsafe is more of a shortcut and often a code smell, and lately since becoming more fluent with it, I'm rarely using casts anymore (though its unavoidable sometimes if you want to avoid T.untyped usages).

I think it has a solid foundation and puts Ruby at the top of my list of good languages if coupled together. It is very performant compared to other typed analysis tools in my opinion.

Please join the Slack community and ask questions if you have any. I'm not part of the Sorbet project or the companies that sponsor it, just an avid enthusiast. https://sorbet.org/en/community


Kotlin would be awesome!


Looks like there's a grammar for it (https://github.com/fwcd/tree-sitter-kotlin) so I think it's on the table!


tools like Greptile (which this seems close to) to understand Git projects were one time use for me (rendering monthly subscription pointless)

once how to properly use github search especially

also not sure about the web design i guess there are some tools where this works


I wanted to say, this is really thoughtful comment and thank you. I love getting ideas like this about the business model and product/market fit.

The second half of the product is a lot more about everyday features e.g. "whose branches collide with mine" or "what are all the upcoming changes in this module", that type of thing. I'm hoping that shores up the long-termism a bit. We'll have to see, though; this whole thing is kind of an experiment and it may just be a miss, or serve a very specialized use case. If you have more thoughts, I'd welcome them.


There's definitely room for a good product here. Idk about advanced use, but from a naive view, git UI and vscode blame plugins are awkward to use.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: