Narthur's ADHD Journal

My task summary automation broke because I was using zod to parse the event but hadn’t written the schema to handle all possible events toggl might send my webhook. I modified the webhook to use safeparse so it doesn’t return a 500 error if an unhandled event is received.

But now I’ve gotten fed up with using express and am switching to Astro for that sweet, sweet file-based routing. Is this a big distraction that’s purely for my own enjoyment?

Yes. Yes it is.

1 Like

Today I made a lot of progress switching from express to astro. It’s already feeling much better. Though I’m fairly certain the switch is going to introduce a lot of bugs in the short term.

1 Like

Clever. I reduce clutter by locally caching the most recent value and only sending a datapoint if either the value or the date has changed.


@philip Ah, good thought! I keep forgetting that now that I’m using a server instead of cloud functions, simple ephemeral caching is a much easier tool to reach for.

1 Like

Update on this: I still find this to be true. However I’ve been working outside my apartment much more frequently lately (read: the library), which makes this trickier. I recently purchased a used iPad from my sister, which solved the issue for a while since I can use it as an external monitor via sidecar. However over time that’s become glitchier to the point that I’ve stopped taking the ipad with me for that purpose. If it was more reliable, though, it would definitely be the ideal portable external monitor for me.

1 Like

I’m trying a new strategy for having a better two-up experience on my laptop. I’ve created a split view in full-screen with Dynalist on one side and Arc on the other. Then I’ve gone into my MacOS preferences and created a keyboard shortcut for “Replace Tiled Window.” I’m starting with cmd-opt-enter–we’ll see if this conflicts with any other keyboard shortcuts I’m not remembering right now. With this setup, I should be able to easily switch between applications while keeping Dynalist anchored to the side of my screen.

I’m already a bit annoyed that this strategy means I have to visually identify the application I want to switch to. My ideal would be to switch to an application the normal way by typing in spotlight or raycast which I think would generally be much faster for me.

1 Like

Ok, now I’m learning Amethyst. I think I’ve nerd sniped myself. :sweat_smile:

1 Like

I’m on macOS and I’ve tried several different window managers and Moom is my favorite. For example, I have a preset for coding, and I hit that hotkey and it brings forward all the relevant windows (e.g. Arc, Code, Hyper) in the correct dimensions and positions. I also appreciate its customizability in terms of how many rows/columns I can use. And I like that I can specify padding between the windows and the edges of the screen (I like this for aesthetic reasons).

(Edit.) Like this:


I’ve finished moving from Express to Astro, though it ended up that I still have Express in the project, since I’m building the Astro app to a middleware that I then execute using Express. This way I still have a server entry point that’s easily in my control where I can do things like init cron jobs on server up.

I’ll definitely acknowledge, though, that sticking Astro on top of Express feels pretty silly. I’m looking forward to when the js community settles on a file-based micro framework that can replace Express. (Let me know if this has already happened and I’m just not aware!) Astro’s working surprisingly well for this so far, but it doesn’t quite feel right given that, at its heart, Astro is a static-site generator that seems to have eat-the-world-vibes NextJS envy.

1 Like

For a while now I’ve been using a Toggl tag “prime” to denote a single project as my focus for the day. Then my automation server took the sum of my prime time and used that to give me techtainment credits for a kind of temptation bundling.

Today I reworked this automation to not worry about Toggl tags and instead simply take the project I spent the most time on for the day and use that time for my techtainment credits.

1 Like
  • Replaced TypeScript type coercion with Zod parsing in telegram webhook handler to try to fix bug
  • Converted several Telegram types to Zod schemas
  • Enabled Vite source map generation in Astro builds to try to improve server error logging
  • Used z.lazy() to fix errors with recursive Zod schemas
1 Like

I’m also considering setting up a GraphQL schema internal to the server to try to make working with third-party APIs less painful (looking at you, Toggl).

As a bonus, it could help me get more familiar with what it takes to build a GraphQL API. Up to this point I’ve only ever consumed, or at best made small modifications to, GraphQL APIs, never built one.

Here’s the code GPT-3.5 suggested as a proof-of-concept for this idea:

const { graphql, buildSchema } = require('graphql');
const { makeExecutableSchema } = require('@graphql-tools/schema');

// Define your GraphQL schema using the SDL
const typeDefs = `
  type Query {
    hello: String

// Define your resolvers
const resolvers = {
  Query: {
    hello: () => "Hello, World!"

// Create an executable schema
const schema = makeExecutableSchema({

// Create a function to execute queries
const runQuery = async (query) => {
  // Execute the query against the schema
  const result = await graphql(schema, query);

  // Return the result
  return result;

module.exports = runQuery;

1 Like

I went ahead and added a proof-of-concept for the internal GraphQL service. Setting it up was relatively painless with the code GPT-3.5 gave me, though I did have to track down a fix for a weird error caused by an interaction between Vitest and GraphQL.js.

Next step will be creating a GraphQL schema for one of the simpler APIs I wrap and then merging it into the main schema I’ll be querying against. I’m thinking TaskRatchet might be a good first candidate, since it’s a simple API and I only have a couple of functions for it currently.

Here’s the code GPT-3.5 gave me as an example of merging multiple schemas together using graphql-tools:

import { mergeSchemas } from '@graphql-tools/merge';
import { makeExecutableSchema, stitchSchemas } from '@graphql-tools/schema';

// Create schema A
const typeDefsA = `
  type Query {
    helloA: String

const resolversA = {
  Query: {
    helloA: () => "Hello from Schema A!"

const schemaA = makeExecutableSchema({
  typeDefs: typeDefsA,
  resolvers: resolversA

// Create schema B
const typeDefsB = `
  type Query {
    helloB: String

const resolversB = {
  Query: {
    helloB: () => "Hello from Schema B!"

const schemaB = makeExecutableSchema({
  typeDefs: typeDefsB,
  resolvers: resolversB

// Merge the schemas
const mergedSchema = mergeSchemas({
  schemas: [schemaA, schemaB]

// Execute a query on the merged schema
const query = `
  query {

graphql(mergedSchema, query)
  .then((result) => {
    console.log(; // Output: { helloA: "Hello from Schema A!", helloB: "Hello from Schema B!" }
  .catch((error) => {

1 Like

It is interesting that in some ways I’m slowly rebuilding Gatsby. Back when I tried using Gatsby for a project it felt super awkward and painful, so I’ll be interested to see if I start running into the same issues now that I’m adding a GraphQL layer. It’s been long enough that my memory on the specifics of what made Gatsby painful are pretty blurry at this point.

1 Like

I’ve been using MacroDroid to create alarms in my clock app on my Android phone whenever it receives a Telegram notification with a :rotating_light: in the message. However this periodically breaks because my clock app only allows 100 alarms and I don’t know of any easy way to delete the previous alarms automatically.

So today I switched from using MacroDroid to AlertMe to create the “alarms” for my notifications. It seems like this is going to work much better.

I also added an /alarm command to my Telegram bot to let me manually schedule an alarm notification to test my setup.

Today I worked on getting my Toggl service into the GraphQL layer. I set up GraphQL code generation, schema merging, and a couple resolvers for the Toggl service.

I worked some more on using the graphql layer, replacing my usage of my toggl getMe function with a query to the graphql layer. Next I’ll be working on configuring things so I can do this type-safely.

And I’ve changed my mind.

Adding a GraphQL layer was definitely a fun experiment, but it quickly became clear that doing so adds a great deal of complexity without actually solving my issue–that it can be difficult to work with third-party API’s, each with varying degrees of quality and documentation.

So I’ve reverted all my work on the GraphQL layer, and now I’m exploring using OpenAPI specs instead. I created an OpenAPI spec file for the TaskRatchet API and used openapi-typescript-codegen to generated a client from the OpenAPI spec. So far it feels really good.

The test will be how it works with something like Toggl Track. Unfortunately Toggl doesn’t seem to have their own OpenAPI specs, so I’ll end up writing my own for that spec, too. The good news is that ChatGPT is pretty good at banging out a rough draft, and then Swagger has a nice online editor that I can use to correct any errors and clean the spec up before adding it to my project.

I’m now working on putting together an OpenAPI spec for Toggl. It’s going to be a bit of a project, but I’m pretty sure that once I’ve got the spec written, using OpenAPI codegen for this will be a lot cleaner and easier than how I’ve been doing it.

Additionally, I updated the shell script I’m using to run the codegen to discover all spec.yaml files in my source directory:

SCRIPTS_DIR=$(dirname "$0")
PATHS=$(find $SCRIPTS_DIR/../src -type f -iname 'spec.yaml')

for path in $PATHS; do
    echo "Generating OpenAPI client for $path"
    pnpm openapi \
        --input $path \
        --output $(dirname "$path")/__generated__ \
        --client axios

I’m continuing to build out my OpenAPI schema for the Toggl API.

One nice thing I discovered is that the OpenAPI spec supports breaking a schema into multiple yaml files, which can then be referenced by their relative path:

    $ref: "routes/me.yaml"

This has made working with the spec much easier, since the file was getting very long!