Skip to main content
Photo of DeepakNess DeepakNess

Raw notes

Raw notes include useful resources, incomplete thoughts, ideas, micro thoughts, and learnings as I go about my day. Below, you can also subscribe to the RSS feed to stay updated:

https://deepakness.com/feed/raw.xml

Total Notes: 238


Google My Business tip to change categories

Came across this interesting local SEO tip on X about Google My Business pages for local businesses. It recommends updating GMB profile category with time, with a few provided examples are:

If you’re in a seasonal industry and your GBP still says “Furnace Repair” in July… congrats, you’re invisible.

If your GBP still says ‘Summer Rentals’ in December, you’re invisible in maps.

And it does make sense.

But I have never tried it, and wouldn't recommend directly implementing this on your main business Google My Business profile.


How to schedule Typefully posts from Google Sheets

If you have 100s of text posts inside Google Sheets that you would like to automatically schedule via Typefully and publish to X/Twitter, Threads, LinkedIn, Mastodon, Bluesky, etc. then it's possible by using this script. And the steps to set this up are:

  1. Create a Google Sheets spreadsheet and put all your posts in a column
  2. Get the script from here, copy-paste inside Google Sheets Apps Script
  3. Get your API key from Typefully and add it in the script
  4. Specify columns for status and Typefully scheduled links in the script
  5. Run the script to see all posts getting scheduled one-by-one

And all posts will be scheduled as per the next-free-slot available in your Typefully account. You can learn more about different options supported via the API on this documentation page.

Also, if you're comfortable using AI for generating posts then you can also use this script to generate posts first and then use the Typefully script to schedule them.


Connect OpenRouter API to Google Sheets

If you quickly want to connect OpenRouter API inside Google Sheets then here is an Apps Script function that you can directly use. There are 100s of AI models from OpenAI, Claude, Gemini, and more that you can use via a single API.

function OPENROUTER(prompt) {
  var API_KEY = 'PUT_YOUR_OPENROUTER_API_KEY_HERE';
  var MODEL = 'openrouter/auto'; // or a specific model id

  if (!API_KEY || API_KEY === 'PUT_YOUR_OPENROUTER_API_KEY_HERE') {
    throw new Error('Set your API key in the script first.');
  }
  if (!prompt) {
    throw new Error('Missing prompt.');
  }

  var endpoint = 'https://openrouter.ai/api/v1/chat/completions';

  var payload = {
    model: MODEL,
    messages: [{ role: 'user', content: String(prompt) }],
    max_tokens: 1000,
    temperature: 0.7
  };

  var options = {
    method: 'post',
    contentType: 'application/json',
    payload: JSON.stringify(payload),
    headers: {
      'Authorization': 'Bearer ' + API_KEY,
      'HTTP-Referer': 'https://script.google.com',
      'X-Title': 'Google Sheets Script'
    },
    muteHttpExceptions: true
  };

  var response = UrlFetchApp.fetch(endpoint, options);
  var code = response.getResponseCode();
  var text = response.getContentText();

  var json;
  try {
    json = JSON.parse(text);
  } catch (e) {
    throw new Error('Bad JSON response (' + code + '): ' + text.slice(0, 300));
  }

  if (code !== 200) {
    var apiMsg = json && json.error ? (' ' + (json.error.message || JSON.stringify(json.error))) : '';
    throw new Error('OpenRouter error ' + code + '.' + apiMsg);
  }

  if (json && json.choices && json.choices[0] && json.choices[0].message && typeof json.choices[0].message.content === 'string') {
    return json.choices[0].message.content;
  }

  throw new Error('No content in response: ' + text.slice(0, 300));
}

While this works for a simple use case, if you have to process 100s and even 1000s of rows then you'll need a more robust script that can keep working in the background. And just so you know, InvertedStone has a script that can do exactly that.

The best thing is the script is always updated with new features and abilities, for example, it can now read images, PDFs, webpages, and has internet access as well. And can also generate images using different image generation models.


Dismiss GitHub fake notifications

For the last few weeks I had a persistent notification on GitHub that won't clear or dismiss no matter what I do. So I started searching about it, and turns out a lot of other people also received the same/similar notifications as I found in this discussion thread.

The proposed solution in the thread is:

  1. install GitHub on your device via terminal (for example, brew install gh for macOS)
  2. run gh auth login, choose HTTPS, and login via the browser, and
  3. run gh api -X PUT /notifications to remove the persistent notifications

I did exactly this and the notification was gone, but I am still seeing the fake repository ycombinatorrr/ycombinator-notification, in my case. I'll keep looking about it and update this note if I find anything.


How to convert Claude Artifacts to HTML files

When I downloaded a Claude Artifact locally, it was downloaded as a <filename>.tsx file and I couldn't preview this without setting up a new React project. So... I searched about this and found a blog post by Simon Willison, and found this repo called calude-artifact-runner that solves this problem.

With just using the below command, I could preview the file in my browser:

npx run-claude-artifact <path-to-file>

And by running the following build command, it also converted the .tsx file to .html file as I wanted:

npx run-claude-artifact build <path-to-file>

I can then normally open the HTML file in my browser at anytime, without needing any additional tools.

Lovely!

Also, I have shared more about the tool and how I used it in this post on X including screenshots.


The opposite of 'vibe coding'

We all have been hearing the term "vibe coding" for months now, ever since Andrej Karpathy coined it, and today I came across a term which might be the perfect opposite of it – "brain coding".

How cool and fits perfectly! Right?

Simon shared this, but he was inspired by this blog post by Thomas Klausner which is very interesting for me.

I used the old, well tested technique I call brain coding, where you start with an empty vim buffer and type some code (Perl, HTML, CSS) until you're happy with the result. It helps to think a bit (aka use your brain) during this process.

Yes, this is the exact paragraph from the blog post.


CSS grid generator tool

You can use https://cssgridgenerator.io/ to create custom grid layouts with easy drag-and-drop layout. The generator allows you to specify the number of columns, rows, the gutter size. And then it gives you the HTML and CSS that you can use anywhere.

Another similar tool is https://tailwindgen.com/ which does the same but for Tailwind CSS. You can get the output in either JSX or HTML with Tailwind classes.

I think, these are very handy tools which are quicker to use than prompting an LLM to do the same.


Adding blank rows after each row in Google Sheets

Manually adding an empty row after each row is possible for a few rows, but won't be possible for 100s and even 1000s of rows. So here is a Google Sheets script that does this with style...

function addRows(){
  var startRow = 1;
  var sheet = SpreadsheetApp.getActiveSheet();
  var rows = sheet.getDataRange();
  var numRows = rows.getNumRows();

for (var i=numRows; i > -1; i--) {
  sheet.insertRowsAfter(i + startRow, NUMBER_OF_ROWS_TO_ADD);
  }
}

The script auto-detects the "range" and automatically adds specified number of rows between all existing rows you have. To use, replace NUMBER_OF_ROWS_TO_ADD with the number of rows you want to add each row, for example, if you write 1 then it will create one blank rows after each row.

You can learn a bit more about doing this in this post that I wrote years ago. In fact, there's even a way to do the same with using just formula.


Remove first/last few characters from multiple files on Windows

Say, you have 100s of files like below, and you want to remove the first 11 characters (i.e. the date) from the start of each files on your Windows computer.

  • 2021-04-25-something-here.md
  • 2022-05-02-another-file.md
  • 2024-11-10-more-file-name-here.md

Doing it manually will take forever, but there's a quick PowerShell command that you can use. And here's the process:

  1. Open the folder, where you files are, in the File Explorer
  2. Press shift and right-click somewhere in the folder
  3. Select the "Open PowerShell window here" option or something similar, and
  4. Run the following command, and it will be done
get-childitem *.md | rename-item -newname { [string]($_.name).substring(11) }

Here I'm assuming that you have multiple .md files, and you want to remove the fist 5 characters from the file names. You can modify the command as per your use case and then use.

Now, if you want to remove the last few characters from filenames, here's how to do it:

Say, you have multiple files with names like below, and you want to remove the last 4 characters i.e. the numbers from filenames (but we've to keep the file extension .pdf here)

  • january1001.pdf
  • feb1002.pdf
  • march1003.pdf
  • april1004.pdf

The similar way, open PowerShell in the folder and run the following command:

get-childitem *.pdf | rename-item -newname { $_.basename.substring(0,$_.basename.length-4) + $_.extension }

Here I'm assuming that you have multiple .pdf files, and you want to remove the last 4 characters from the filenames, while keeping the file extension .pdf.

Please note that this process is irreversible, so I would recommend that you copy all the files to another folder and then try running these commands to avoid any mistakes.

Also, this command works only for the same type of file i.e. files having the same extension. If you have to rename multiple files of different extensions, you can repeat the process for each type of file.


JavaScript library dual-licensing business model

When browsing, I came across this post by Sachin Neravath who is earning ~$400/day from a JavaScript library. Cool, right? I looked more into the product and it's really interesting.

Sachin created the lightGallery library with GNU license but if someone needs a commercial license, they need to pay the price mentioned on the pricing page. Also, in this post, he briefly explained how exactly this works.

One issue here is, it's difficult to know if someone is using the library for commercial use without paying or not. But I think, considering most people are honest, this shouldn't be a big issue for such a business model.

While researching about this, I also came across this LinkedIn post from Sachin from 2 years ago. He shares some more insights about this in the post.


Hugeicons icon library

Came across this post on X where they have used Hugeicons to design a dashboard and the icons looks crazy good.

So I looked into Hugeicons and this is how to install and use it:

npm install @hugeicons/react

There are more than 40k icons available but only 4k are available for free, others are not available for free. But I think there are enough free icons that I can use in my simple projects.


One-click Clerk auth in Cursor

Clerk has enabled a way to directly open the prompt in Cursor by clicking on the "Open in Cursor" button on different docs pages. I got to know about from this from the post on X by Clerk itself.

For example, if you visit Next.js Quickstart (App Router) page, you will see the button to directly open the well-written prompt in Cursor. I think, it will be better to use the properly tested prompt in Cursor instead of manually writing the prompt to implement Clerk authentication in apps.


Screenshot tool shot-scraper package

I was reading this post designing agentic loops by Simon Willison and came across this Python package called shot-scraper. It's a Python specific command-line utility that automates the process of taking screenshots of websites.

By the way, it's a wrapper around Playwright, and here are some cool features:

  • Taking automated screenshots of entire web pages or specific elements
  • Capturing screenshots of specific CSS selectors or page regions
  • Supporting various output formats including PNG and JPEG with quality controls
  • Handling authentication contexts for taking screenshots of protected pages
  • Taking screenshots at different viewport sizes and device scale factors

It can be installed via below commands:

pip install shot-scraper
shot-scraper install  # Installs the required browser engine

I think, it's going to be very useful for some programmatic SEO related projects which requires taking screenshots of webpages. I am yet to install and use this, but it looks very promising when I went through their docs.


The Accidental CTO by Subhash Choudhary

Came across this cool eBook The Accidental CTO written by Subhash Choudhary, the Dukaan CTO. He shares the story of scaling Dukaan from zero to a million stores, without even having a CS degree.

He will be discussing the below topics in the ebook which will be an interesting read.

  • Scaling applications: How we went from thousands to millions of users without falling apart.
  • Replication, sharding, caching, queues: When to use them, when not to, and what tradeoffs they carry.
  • Observability as survival: Why metrics, logs, traces, SLAs, and SLOs aren’t optional — they’re lifelines.
  • Resilience engineering: Circuit breakers, retries, graceful degradation — designing for failure, not against it.
  • The hidden costs of cloud: Why at scale, your AWS bill can become your biggest investor, and when it makes sense to go self-hosted.
  • The consistency/availability/latency triangle: Why you can never fully win, and how to navigate the tradeoffs in real systems.

I have started reading it already, and loving it so far.


Localhost visual editor for Cursor AI

Came across this post from @pavitarsaini who created a Chrome extension which can be used to visually edit some part(s) of the webpage via Cursor. It's explained as:

Click any element on your dev site → describe what you want changed → it automatically sends the edit request to Cursor in the background with the element context.

It works by utilizing Cursor's deeplink feature like below:

cursor://anysphere.cursor-deeplink/prompt?text=

There's a video and some more info on how this works shared in the post.


Updating self-hosted n8n

I hadn't updated my self-hosted n8n instance for over 6 months, so I decided to do it today and didn't realize it was this easy. I just ran a bunch of commands, and it was successfully updated:

  1. sudo apt update && sudo apt upgrade – refresh package lists and install OS updates on the server.
  2. docker pull docker.n8n.io/n8nio/n8n – download the newest n8n image.
  3. docker ps -a – list all containers so you can see the n8n container ID and name.
  4. docker stop [CONT_ID] – stop the old n8n container.
  5. docker rm [CONT_ID] – remove the stopped n8n container.
  6. cd n8n-docker-caddy/ – go into the folder that has your docker-compose.yml.
  7. docker compose pull – fetch the latest images defined in docker-compose.yml for both n8n and Caddy.
  8. docker compose down – stop and remove the running Compose stack, keeping your volumes and data.
  9. docker compose up -d – start the updated stack in the background.

And done! I'm now running the latest n8n with your existing data and config.


Indie hackers should do SEO

I came across a post on X on indie hackers working on doing SEO for the growth of their SaaS. The post says:

why so few indie hackers do SEO?

  • ads require big budget
  • audience building requires personality
  • cold outreach requires having no shame

and 95% of SEO is just chill keyword research and coding

I also saw this post about doing paid advertising from Simon who runs FeedHive.

Not bad.


Are LLMs AI?

Came across this post from Simon Willison where says that:

I often encounter people who firmly believe that "LLMs aren't actually AI"... do those people think there exists technology today that DOES count as AI?

I think, LLMs are nothing but AI. And I even replied to the post with the following:

Depends on how we define intelligence.

A lot of human intelligence is just predicting what comes next – which is exactly what LLMs do.

So yes, I think, LLMs are AI.


Remote FileVault unlock in macOS Tahoe 26

macOS 26 adds a super handy backend change: you can unlock FileVault over SSH before the system fully boots. That means real lights-out access for studio machines.

What it enables

  • Limited SSH runs at pre-boot. Log in with the Mac’s local username and password to unlock FileVault, then the system finishes booting.
  • After unlock, normal SSH and Screen Sharing work.

How to set it up

  1. Turn on FileVault.
  2. System Settings → General → Sharing → turn on "Remote Login" (SSH).
  3. Reach the Mac over the same network or your own VPN – this is not a public-internet thing.

Flow

  • After a reboot, the Mac waits at the login screen.
  • From another Mac: SSH to it → enter the local creds → disk unlocks → full boot → Screen Sharing connects.

Wi-Fi didn't work but plugging into Ethernet made it work reliably.


Enable bash/shell mode in AI CLI coding tools

From this post by Ian Nuttall on X, I just learned that typing ! in most of the AI coding CLI tools like Claude Code and Codex enables you to write bash/shell commands without requiring you to open another terminal for the same.

In fact, I thought this multiple time that there must be a way to quickly run the bash commands in the same terminal window. And turns out, there's already a solution for this. Wow.

Apart from this, I also learned that typing # and writing something can quickly add it in the CLAUDE.md file.


Ussing Tailwind CSS child selectors

When using Tailwind CSS, the both below code snippets for an HTML table show the same thing... but the second one looks cleaner here. It's called using Child Selectors in Tailwind CSS as being discussed in this thread on X.

<table>
  <tr>
    <td className="px-3 py-2">CSS</td>
    <td className="px-3 py-2">Great</td>
  </tr>
  <tr>
    <td className="px-3 py-2">Tailwind</td>
    <td className="px-3 py-2">Fine</td>
  </tr>
</table>
<table className="[&_td]:px-3 [&_td]:py-2">
  <tr>
    <td>CSS</td>
    <td>Great</td>
  </tr>
  <tr>
    <td>Tailwind</td>
    <td>Fine</td>
  </tr>
</table>

And I liked the Child Selectors approach because I don't have to repeat the same classes again and again. However, some people do not like this at all and you'll find that in the X thread I linked above as well.