June 16, 2025
JUST MADE THE FIRST RELEASE 🥳
Check out the demo video, it's a really cool project. I will be using this instead of Slack myself.
HackCLI now uses a cache to cache users and channels it encounters to limit the amount of api calls and make the app FASTER. User can now tag/mention a channel or a user himself, but only if this user or channel is cached. You can do this by just writing @Username or #channelName and this will be converted to a slack ping/tag/mention (idk how to call that properly lol). Preparing for first release :)
(No image of the app because I changed a bunch of stuff and it doesn't work currently) Previously if someone mentioned a user or channel in a message (@user or #channel) the app rendered something like what's visible in the image, basically the channel's id with some additional characters. I now styles these mentions specifically, they are of different color than the rest of the text and I display the actual username or channel name, not the id/
The other thing which I have been working on is implementing a cache to the app. I had something similar but it was only for the current session and only stored usernames. Now I will have a cache file which I create on the first run and load the cache io the app on following runs. When getting all the info for the first time from slack I show a loading screen for the duration of the process, like couple dozen seconds I would guess, depends on how many channels and dms the user is in. Then all the following runs load instantly and load fresh information in the background and update it from the cached info that might be stale, the app will now be much faster than before basically. I am working with a json file for the cache currently, but I will consider using a db if need be later, the file works for now I think, we will see tho. I still have a lot of work to do on that matter and I have to restructure a lot of stuff to work with the new concurrent or synchronous system depending on the run.
I did a bunch of different stuff. The background color of my app was the user's terminal color, but now the app has a theme specific background independent of the terminal background. This was harder than it seemed, because i had to stretch all the components so there are no gaps between them and apply the background color to each of them. I also added deleting and editing your own messages just now, because I forgot to do that earlier. The goal is to make HackCLI completely independent of the slack desktop app, so the user doesn't have to touch it at all and can do everything from the terminal version. To follow up on this idea I also added joining and leaving channels, so I don't have to use the slack app for this anymore.
The app now resizes very well so the user can use it in a smaller terminal window if need be. I deleted the old auth system and login command that I was using with the slack user token at first. I created a new init command which creates a config file on the users machine with the cookie he provides and token we get based on that. I will have to add a guide in the README to get the slack cookie, because that's the only part the user is required to do manually. With init you also choose the theme of the app (I ALSO ADDED THEMES!) which you can change anytime in the config file.
You can now open a thread in a new window that pops up next to the chat and write your reply in it's input. Just like in slack. I reused the existing chat and input components but had to adapt my architecture slightly for this to work.
There is still a bug where the app freezes and I am unable to do anything unless I close the terminal. I have no idea why that's happening, so I have been just kind of ignoring this, because i have no idea when that happens and what's causing this. Also sometimes the usernames and not fetched and still displayed as ... after a while, I would need to dig deeper to understand if that's a bug too and I can make them all load and faster if it just has to take a while to load for some usernames and that's normal. I will now add some smaller updates to the app and after I am content with the features, I will make sure everything is working as expected, there are no bugs and I will ship
For the most part I was having a lot of issues with the apps performance. Channel like announcements wouldn't open at all, or later it would be really slow, but I made the rendering logic more sophisticated and the performance is consistent across all channels. We now get the replies only for one parent message when a user tries to open it's thread. There were also some smaller bugs that made the app freeze, don't think the app is bug-free now, but I have fixed a lot of them.
Alright, so I have been mostly working on the visual right now. Just like is slack, the channels are now bright when unread and dimmed if no new messages were sent in them since your last visit. I added an icon next to a DM showing the presence of the user (active or away), and it changes live (every 3 minutes, because there isn't an event for that afaik). I also didn't like how the chat looked, so I added a border to the messages and different colors all over the app. Next I will be working on adding proper themes to the app, so everyone can customize it to their liking. I currently use a rose-pine ish theme
Added removing and adding reactions to a message. A modal pops up where you enter the reaction to be added, or removed if it already exists. I also spent a lot of time trying to make the sidebar look better. I am not sure if that's better than what I had before, but let me know. The plan is that the channel names will be bright and bold when unread and dimmed otherwise. I will also try to add icons showing pings in channels and user's activity for DMs. I also did some other smaller stuff
Added DMs - the whole point of migrating to the xoxc token. Added headers in the sidebar to make a section for channels and DMs. The DMs work just like channels. I had to fix a lot of bugs and panics along the way, so this took a while. I also cleaned up the code, moved all slack api calls to one folder and created reusable functions to use the slack api.
The essentials of slack are done (excluding replying or adding a reaction, will do that now) so what's left to do now is to make a clean login experience, add some other features if I will decide it's worth it. I am thinking about redoing the whole tui pretty much. Right now everything is very simple, text with a green line to indicate selectability pretty much, both sidebar items and messages. I am tempted to add some colors, borders etc to make it look more glamorous. This will mean that less messages will fit in the chat and channels in the sidebar, but the visuals might just be worth it, and the UI is the single most important thing if you want your project to be voted on, so I guess I gotta do it.
Oh and I would love if my app would support images. I could display user profile pictures, reactions, pure bliss. But it might be really hard if even possible to get it to a viable quality, so if ever it will probably wait for another release.
I can't believe I am saying it but i finally MIGRATED TO USING A XOXC TOKEN. I did some hacky workaround to make the slack-go/slack package work with the xoxc token and cookie for the web API, but the websocket was way more stubborn. I tried with socketmode, RTM API, and all that, but finally made it to work so dropping the code for this bad boy in the image in case any thief wants to copy my project /jk
Made a new branch and will probably merge it soon, but no need to hurry.
I have done some major changes to the structure of the project. I will be probably moving more towards an all-in-one slack like app experience instead of many commands for different functionality. So among all I added a core folder to hold all the important structs accessed by other packages. The api package will now handle all the api calls to slack. I deleted some of the commands and the main app runs now with just hackcli
. Now I am trying to migrate to using a xoxc token which will just level up the app giving it more rate limits, permissions etc. I have to use it to add DMs basically.
Eyo it's ya boy again! Let's pretend it has only been a day since my last devlog.
I now update the TUI if a message is deleted or edited and when a reaction is removed.
I also (HOPE) I finally fixed the scrolling and selecting messages using keyboard. I had some trouble making the correct logic to skip the hidden messages (replies if a thread is collapsed) and stuff like that.
Oh, I forgot I also restructured the files again. The names now makes more sense and I have split them even more. I will be doing that from time to time as the project gets bigger.
Heyo. Imma start devlogging more frequently, maybe that will differentiate me in the voting MATRIX. No promises tho. I don't devlog just for the sake of it, only when I have quality stuff to deliver.
Back in the topic. I have added a bunch of stuff so I will list all I remember:
I added threads - for now they are inline in the chat, but I might make it like it's done in slack, so a new window with the thread would pop up next to the chat. I also made messages in the chat selectable with a keyboard, this is crucial so you can open and collapse threads or in the future add reactions or replies yourself. Keyboard is what I am primarly aiming for, bc we all know everything you can do with a mouse you can do faster with a keyboard, but I will probably add mouse support too later so you can use either or both. Reactions are now part of the app too, you can't add them yourself yet, but they are displayed as a box under the message they belong too. Unfortunately I cannot display reactions other than the unicode emojis, and most people use the workspace ones which I can't display in the terminal, so emojis are the string representation of them, like :yesyes: for example. I almost lost my mind trying to fix the layout of the chat. Idk how it's happening, but sometimes stuff just breaks for what seems like no reason. Yeah... I had a couple mental breakdowns, shame I don't have a rubber ducky... Uh, I almost forgot I restructed the file structure a little bit, because the file for this main command was like over 800 lines so I split it into multiple. Will have to refactor the code more and the structure again, rename some files and stuff like that, need to get it all to look pretty, bc this is the equivalent of a clean desk at your office - can give you a performance boost for real when clean.
So that's it. I will try to lock in and devlog every day, just for you - YES YOU WHO SEES THIS
Had a fight with websocket. Came back victorious I would say.
So previously, I was only really displaying message history when a channel was opened, because... websocket was in a bad mood I guess. Got an email from slack a couple of times saying they disabled receiving events for my app because they detected some issues. We will see if that's resolved, but for now the chat is functional. Websocket sometimes gives me messages in the wrong order, especially if they were written in very quick succession, so I am now just sorting the messages myself so I can be sure they will always be displayed in the correct order. I also saw when logging to see if everything is as expected, that I am burning through the rate limits when fetching usernames so I can display them next to a message. For new live messages it was all okay, but when fetching history, I would render a bunch of messages at the same time, and the fetch for a username would not finish before the other go routines handling other messages from the same user would try to get the username. TLDR now I fetch user's username only once per user. And I also made some other small adjustments to improve efficiency of the app or stuff like that.
What's left now apart from maybe some better styling, is adding threads. This won't probably be easy so it might take a lot of time which will probably not be tracked by hackatime because I will be thinking rather than spamming keyboard :(. Oh I hate this, under like 50% of my time spent coding is actually tracked probably :/
I will put some logs as the image as the TUI didn't change
This is starting to look like something, no hope is lost.
You can focus different components with tab or shift+tab. When writing the command you specify a channel which will be opened on app start. When that happens, or you choose a different channel in the sidebar, the chat history for this newly opened channel loads, after that it's up to this LAZY ASS websocket SLOP to deliver live messages when they are sent in the original slack channel. I had a lot of issues with websocket (as you can probably tell), it was giving me messages in random order, from before the app even started and all sorts of stuff. I don't think everything is sorted out in that regard, so I will have to take a closer look at it.
Next to implement would be the input, bc it currently does nothing, but that will be quick. Also I am working on a userCache, currently after a message is rendered the user's ID is displayed instead of their display name for like ~200ms, then it's rerendered with the proper display name, but next time this user writes a message it will instantly have the user's display name text to it, thanks to the caching. Maybe I will also add all the users to the cache in the background while the app is running, unless that's not too overkill.
Sad to end on a sad note, but unfortunately my app is inherently limited by the slack rate limits (😠😤) aside from the slack api limitations in general. I am not sure how far I can take this app, if it's going to be usable by more people simultaneously than just me (if anyone would ever even want to use it). Either way, I WILL make it right. Maybe I will have to use some tricky, sussy, hacky ways, maybe drop some people d*ad (can I say that here? let me know in the comment or smth, don't want to get my project banned or smth) in the process, but I will get where I need to get, understood? Aight, see ya tomorrow
ROGER THAT
Aight so I have been working on the main command: hackcli channel open. Probably gonna change this command name or the structure of the commands entirely again because it sounds clunky. A LOT HAS HAPPENED.
So basically with this command a TUI opens where you can interact with your slack channels just like in slack (sidebar, chat with messages and input to type a message). First I split up this program into four smaller ones, but then I decided to have just one big program as everything was easier that way. I learned a lot about websocket and that kinda stuff because I use that to get notified from the slack api when a message is posted to a channel for example so I can display it live in the TUI. I also used go routines and channels for the first time, not complex scenario but still learnt from it. Currently the messages don't appear in the chat for some reason, will have to check why that is and fix. The UI looks like shiet, but I am working on it, will look good in no time, trust me.
I HAVE BEEN TRYING TO UPDATE A CUSTOM PROFILE FIELD FOR 5 HOURS...
SPOILER I FAILED **END OF SPOILER (if you know how to do that you can comment)
Yeah clicking enter now actually updates your slack profile and shows a confirmation message, but I had to remove the Fav Activities field. The slack go sdk failed me and I had to make some http requests manually to the slack go sdk. Tried literally everything possible at this point to update the custom field, but idk it's impossible, everything was correct, change my mind. It's crazy how many weird debugging methods I am using XD, I won't ever learn the correct way to debug code LOL.
I'm writing this in the middle of the night. Added an edit command and a first argument being profile (hackcli edit profile). Basically you can edit some of the more important profile information of yours through a nice UI. I got to know Bubble tea from it's evil side and am pretty discouraged. There is a high chance I am overcomplicating everything or doing it the completely wrong way, idk but the way bubble tea does it's stuff seems really wrong coming from javascript and react. Either way... this command is not yet finished, I have to figure out how to update the user's profile info, because for some reason there is no simple method for that in the go slack sdk.
Quick update INCOMING!
The login command now checks if the user already has a valid slack token in the config.json file (if the user is logged in). If user is logged in the cli prompts him that he can use all features of HackCLI now and if user is not logged in they will complete the login flow
A mobile app made with react native. No productivity app was right for me, so I decided to create a better one myself. It has a journal (something I have wanted to have for a long time), and most importantly a beautiful timeline where I can structure my day. Every task also has some specific features you can enable, for example you can track your reps and breaks in the gym.
At first I was so overwhelmed with cobra and bubble tea that it was crazy, but after some time it wasn't that bad. I decided to have a different command for a different feature. Now I can think of it as creating many smaller apps, instead of a big one, this makes things easier. SOOO chat, I created the first command - LOGIN, basically the user authorizes the HackCLI slack app that I created, gets the token from a backend function, pastes it into the cli and then we create a config file on the user's machine with the token and all other commands will be able to use this token to do stuff on the user's behalf (the user will be logged in). So yeah, will only get easier from now on, right? RIGHT?!
OH, btw I have not tested this command at all LOL, so it is bound not to work, as per usual, because never works on the first try for me, but little debugging will do the trick.
I tested and debugged the app and got it to work. Had to add a new scope so the cli can get the user's current status and emoji to make it the initial value of the text inputs. I also fixed the layout with empty lines to make it more readable. I made a script to inject slack secrets at build time so they work for all users and are not displayed on github. Lastly I distributed the cli on npm and made a simple installation guide.
The app flow is finished, now I have to debug the app and see what needs improvement (currently there are some errors). I did the same project but in Go to see what feels better. This was much faster because I am familiar with js and already knew what to do.
Change your slack status in seconds from the terminal. Project to learn typescript and Ink. This project was not vibe-coded 🤮, used AI only to help me distribute the cli and check if my code is correct.
Finished the app and distributed it with goreleaser. I added the rest of the app flow: input to enter the new status, another for status emoji (fallback if the terminal doesn't support emojis) and confirmation and error messages. The app calls the slack api to update user's slack status and get their name to greet them. I also created an extensive installation guide, but simplified it later.
Understanding the BubbleTea framework took some time and trial. I started by creating a slack OAuth flow so I can log the user in. Had a lot of problems with retrieving the code through a redirect uri. Tried running a go server with ngrok but that didn't work too well so I deployed a vercel function and now slack redirects to it and user has to copy the code given by slack and paste it back into the terminal.
Roses are red, slack is sluggish, but HackCLI will make you forget about that rubbish. Slack terminal client for Hack Clubbers - faster than alt-tabbing to an already slow Slack. Check channels or DMs, ping staff or do whatever the heck you want all without leaving your IDE. You won't want to go back For clarity, I didn't use AI much, primarly when 10 rubber duckies were not enough and my synapses were on fire (when debugging of course). Please check out the demo video in the README or latest devlog for an easy look at the project if you are not keen on installing it (though I really put a lot of heart into the docs)
I added a clear progression to the timeline. Every task in the timeline up to the current moment is colored and every task in the future is grey with just the color accents. Also connected all tasks with a progress bar which behaves just like the tasks color wise and has a smooth gradient from one task's color to another's when between tasks. I think this is an essential visual upgrade so the user can roughly know how much of a task is left or how far in the day is he.
Really just transformed a list of tasks into a timeline:
- Added date sections to indicate when a new day starts - Added gaps beteen tasks indicating how much free time there is between two tasks - Added timestamps when every task starts and ends - Just one timestamp if tasks are right after each other (no duplicate timestamps showing same time) - Added task's timeframe and duration below it's name - Fixed invalid timeframe check in TaskSettings - TaskSettings now doesn't allow to have overlapping tasks - + more that I don't remember
You can now add a new task by configuring the settings in TaskSettings or update an existing task. I added error messages so the user can not save a task if it doesn't have a name, emoji etc. I also sorted the tasks array by date and time so that the earliest task is first. I tried to move my project to a location on my windows system (was on Linux system, I am using wsl) so I can create EAS builds locally and not wait 6hrs in a cloud queue but the app was reloading so slow due to the wsl bridge that I went back to my original folder. Thankfully tho hackatime didn't break and correctly tracks my hours for this project after all that.
Added a delete button to a Task and made a few changes. Created settings for a Task with a name input, start and end time, duration, date, color and emoji. I used a DateTimePicker package and a reanimated-color-picker library for the respective settings. It doesn't seem like I did a whole lot, tbh I am probably bad at making UIs, but this just takes time for me.
Added firestore security rules. Started creating the timeline page: added a header with a settings page where you can log out, used FlashList for the timeline, created a Task component with a ThreeStateButton that indicates if the task is done, not done or kinda done.
There is now authentication in my app. Worked on the sign in methods, used a vercel function to safely handle github client secret and get the access token (tried google cloud functions before). I also fixed some redirecting issues with the github sign in, made sure that user accounts are created in firestore when user signs up. Hope it's not a big problem this devlog was posted after more than 4 hours of coding since the last one, I wanted to have the authentication finished and have something to show.
This was widely regarded as a great move by everyone.
Played around with Firebase and implemented saving to Firestore (there are still some issues)
I finished the journal page - the first page in my app. I added the last feature to it - a list of improvements you want to make.
This is my first devlog where I talk about everything I did so far for the 23 hours that are tracked on my project (at the beginning I didn't know we had to make devlogs). I know the small amount of stuff I made might not justify the 23 hours, but some things took me hours to figure out. Sorry that the audio is so quiet (hope it's bearable) and that I'm swinging on my chair so much (I might have ADHD or something).