Home/Writings/Systems Programming

From Discord Bots to Flirting with Kernels: My Unorthodox Path into Systems Programming

How a simple Discord bot at age 15 during lockdown taught me more about real engineering than any roadmap ever could. The story of project-driven learning, rejecting shortcuts, and ending up building Rust shells and ptrace tools.

Figure 1A working loop for technical inquiry: observe the system, reason about its constraints, and build to test the model.

It was 2020. The world was locked down. I was 15, glued to Discord, playing games with friends, and generally trying to survive the boredom. One day, a Discord bot replied to a message in a server. It felt like magic. Not the kind of magic from games — real, interactive, programmable magic.

That single moment changed everything.

I didn't start programming because I wanted to "become a software engineer." I started because I wanted that bot — my own bot — to reply to me and my friends. That innocent curiosity launched a journey that took me from npm install discord.js to building a custom shell in Rust (Jasmine), syscall replay engines with ptrace (SysRift), TCP honeypots handling adversarial traffic, Raft implementations, and now flirting with kernel interfaces and eBPF.

This is not a "how I learned to code" success story. This is the story of why project-driven learning, refusing shortcuts, and chasing things that must exist beats every curated roadmap.

The Spark: A Broken Tutorial and the First Real Crisis

I followed a YouTube tutorial like any excited kid. npm init, npm install discord.js, copy some code, and boom — my bot was online.

It worked... until Discord rolled out a major update to the library. Everything broke.

Most people in my position would have:

  • Found another tutorial
  • Switched to an easier bot framework
  • Or given up

Instead, I got pissed off and made a decision that defined my entire approach to engineering:

I had to learn JavaScript — for real. Not just the syntax I saw in the tutorial, but async/await, promises, event loops, error handling, managing secrets (no more hardcoding tokens like an idiot), and proper project structure.

I wasn't following a "JavaScript roadmap." I was learning whatever the bot demanded to stay alive.

Don't chase roadmaps. Chase problems that force you to grow.

This was my first taste of ownership. The bot wasn't a toy anymore. It was something I deployed, something other people interacted with, and something that could (and did) fail publicly.

The Anti-Roadmap Philosophy: Chasing the Thing, Not the Identity

Most beginners follow the Sacred Roadmap™:

  1. HTML/CSS
  2. JavaScript
  3. React
  4. Node.js / Express
  5. "Now you're full-stack!"
  6. Docker, Kubernetes, CI/CD, clouds...
  7. Endless FOMO: "Am I missing GraphQL? TypeScript? The new hot framework?"

Every step brings a new identity crisis. You finish basic web dev and think you're ready, then discover React and feel behind again. This creates tutorial hell and shallow knowledge.

I skipped that trap entirely because I wasn't building an identity. I was building a Discord bot that needed to work.

  • I learned JavaScript because the bot required it.
  • I learned proper backend patterns because users were interacting with it.
  • I learned deployment and secrets management because hardcoding tokens is stupid and dangerous.
  • I learned about rate limits and APIs because Discord would punish my bot.

There was no FOMO because my focus was narrow and deep: Make the thing not suck.

This mindset — "the project is the boss" — has been my guiding principle ever since.

From Bots to Real Systems Pain

As the bot grew, so did the problems:

  • Handling concurrency and race conditions in command processing
  • Persistent storage (databases)
  • Scaling to more users and features
  • Building simple web dashboards to control the bot

College (KIIT) gave me more structure, but I kept the same approach:

  • Built a hackathon platform used by 250+ students → real traffic, performance requirements, async workflows
  • Worked on ML deployments to edge devices (Jetson Nano) → constraints force tradeoffs
  • Led teams and workshops on CI/CD and performance optimization (55% load time reduction)

Every project reinforced the same lesson: Abstractions leak. Future-you will be paged at 3 AM. Assume failure and adversaries.

The Rust Awakening: When JavaScript and Python Weren't Enough

By 2023-2024, I started hitting the limits of higher-level languages for the kind of control and safety I craved.

I wanted:

  • Memory safety without garbage collection pauses
  • Fearless concurrency
  • Explicit control over the machine
  • Tools that wouldn't explode under adversarial conditions

Rust felt like the natural next step. Not because "it's trending," but because my projects demanded it.

Building Jasmine: A Shell from Scratch

Writing a full shell in Rust was brutal and beautiful. It forced me to deeply understand:

  • Command parsing
  • Process execution and forking
  • Pipelines and redirection
  • Job control
  • The Unix process model

No hand-holding. The compiler became my harshest (and best) mentor.

SysRift: ptrace and Dancing with the Kernel

This project took it further. A syscall replay engine using ptrace.

I was now injecting memory, replaying system calls, dealing with nondeterminism — basically flirting with kernel territory from user space.

This wasn't "learn OS concepts for an exam." This was "I need to control and understand reality at the syscall boundary."

Other projects followed the same pattern:

  • EchoTrap: TCP honeypot designed to handle timing attacks and 2M+ events
  • QuantumLock: Post-quantum cryptography with real benchmarks and constraints
  • Raft implementations, compression tools under tight performance budgets

Each one dragged me deeper into systems programming because the thing I wanted to build demanded it.

Abstractions become useful only after you understand what they are hiding.

What This Path Taught Me (That Roadmaps Can't)

  1. Vertical Depth Beats Horizontal Breadth
    I know async deeply because my bot needed it. I know process management because I built a shell. Knowledge compounds when attached to real pain.

  2. Shortcuts Create Longer Problems
    That first Discord.js rebuild taught me this forever. I still refuse to cargo-cult code.

  3. Ownership Changes Everything
    When the system is yours, failures feel personal. This builds the "I'll be the one paged" mindset early.

  4. No Identity, Just Problems
    I'm not "a Rust programmer" or "a systems engineer." I'm someone who builds things that must exist and must survive reality.

  5. Boredom is a Signal
    When I get bored, it usually means I need to make the current project harder or go one layer deeper.

Looking Forward: Deeper into the Kernel

I'm currently exploring eBPF for safer, more efficient kernel interaction without the overhead of ptrace. The goal isn't "learn eBPF" — it's to build better observability, security, or debugging tools that solve real problems I care about.

The path continues: distributed systems at scale, runtime internals, maybe even toy OS or hypervisor experiments. Whatever the next "thing that must exist" demands.

Final Thoughts: Advice for Fellow Builders

If you're starting out:

  • Don't chase roadmaps. Chase something that excites you and must work.
  • When it breaks (and it will), resist the shortcut. Go deep.
  • Build in public. Document the pain and the lessons.
  • Reject identity traps. Be a problem owner, not a stack collector.

The industry needs more engineers who think like defenders of fragile systems, not tourists collecting technologies.

My Discord bot at 15 wasn't a beginner project. It was a crucible. It taught me that real engineering starts with ownership, curiosity, and the willingness to suffer through the hard parts properly.

If a bored 15-year-old gamer during lockdown can end up here, imagine what you can do when you find your magic.


Akshat Chauhan
Building systems that survive reality.
Portfolio | GitHub | X

Last updated: June 2025

Continue reading
Programming · 8 min read

Why Rust for Systems

A practical note on why Rust changes the shape of low-level engineering work.

Read note
Networking · 7 min read

Subnetting Finally Clicked When I Stopped Memorizing It

For years I treated subnetting as a collection of formulas. It only started making sense when I stopped memorizing rules and started seeing address space as blocks.

Read note
Distributed Systems · 11 min read

Lessons from My First Distributed System

The small surprises that appear when a program stops living in one process.

Read note