Live Demo: SDD vs Vibe Coding in 10 Minutes

Live Demo: SDD vs Vibe Coding in 10 Minutes

This is the demo that makes the difference tangible. Two approaches, same feature, same AI. The contrast speaks for itself.

Use this for conference talks, team workshops, or to convince a skeptical colleague that the spec-first approach is worth the two minutes it takes.

Setup (before the demo)

  • Have a project with Planu installed in Claude Code
  • Have a simple feature idea ready: “add dark mode toggle”
  • Ideally have two terminal windows side by side

Part 1: The Vibe Coding Approach (3 min)

Say: “This is how most people use AI coding tools today.”

  1. Open Claude Code in a project without Planu
  2. Type: "Add a dark mode toggle to the settings page"
  3. Watch Claude write code
  4. Ask the audience: “How do you know this is correct? How do you know it is done?”
  5. Point out: There is no checklist. No verification. No way to track that the right thing was built.

Say: “This works for prototypes. For production features, you need something better.”

The issue is not that Claude wrote bad code. The issue is that you have no way to know whether it wrote the right code without reading every line yourself.

Part 2: The SDD Approach (5 min)

Say: “This is Spec Driven Development with Planu.”

  1. Open Claude Code with Planu connected
  2. Type: "I want to add a dark mode toggle to the settings page"
  3. Planu creates a spec — show the acceptance criteria on screen
  4. Say: “Notice these acceptance criteria. The AI now knows exactly what ‘done’ means.”
  5. Say to Claude: "Approve this spec" — show Planu moving to ‘approved’ status
  6. Claude implements the feature against the spec
  7. Run: validate SPEC-XXX
  8. Say: “This tells us whether the implementation matches the spec. Not vibes — verification.”

The key moment: When you show validate passing, the audience sees that “done” is a binary state, not a feeling.

Part 3: Why This Matters (2 min)

Key points to land:

  • “When something breaks in production, you look at the spec — not trawl through chat logs”
  • “When a new developer joins, the spec documents what was built and why”
  • “When you have 50 features in flight, Planu tracks all of them — not just the one you are looking at right now”

Close with:

“Planu does not slow you down. It makes your AI more reliable. That is the difference between vibe coding and spec driven development.”

Q&A Preparation

“Isn’t this just extra documentation overhead?”

The spec is the contract, not the docs. It takes 2 minutes to approve and saves hours of re-implementation when the AI builds the wrong thing. You would rather find out the spec was wrong before implementation than after.

“What if I am prototyping?”

For throwaway prototypes, skip the spec. Planu does not force anything — it is there when you need production quality. The workflow scales down gracefully.

“Does this work with Cursor, Windsurf, or other tools?”

Yes. Planu works with any MCP-compatible AI tool: Claude Code, Cursor, Windsurf, Zed, Cline, Continue, and more. One installation, all your tools.

“How long does writing a spec actually take?”

About 2 minutes for a typical feature. Planu generates the initial spec from your description — you review and approve it. The overhead is genuinely small compared to the verification it provides.

Adapting This Demo

For a 5-minute slot: Do only Part 2. Skip the Vibe Coding comparison and just show the SDD workflow working. The validate output is the most impressive part.

For a 30-minute workshop: Add a hands-on section where attendees install Planu and run through the workflow themselves. The npx @planu/cli install command gets them started in 30 seconds.

For a skeptical audience: Lead with the question “How do you currently verify that AI-generated code is correct?” Most people do not have a good answer. That question frames the entire demo.

Planu — Spec Driven Development for AI coding agents. Get started

LeetCode Solution: 283. Move Zeroes

Don’t Let Zeroes Hold You Back: Solving LeetCode 283 In-Place!

Hey LeetCoders and aspiring developers! 👋 Vansh here, and today we’re tackling a classic array manipulation problem that looks simple on the surface but teaches us a ton about efficient, in-place algorithms: LeetCode 283, “Move Zeroes.”

This problem is a fantastic entry point into the world of two-pointer techniques, a common pattern in competitive programming and everyday software development. So, let’s dive in and conquer those pesky zeroes!

🚀 The Problem: Moving Zeroes

You’re given an array of integers, let’s call it nums. Your mission, should you choose to accept it, is to rearrange this array so that all the 0s are at the very end.

But there are two crucial rules:

  1. Maintain Relative Order: The non-zero elements must keep their original order. For instance, if you have [1, 5, 3], they should remain 1, 5, 3 and not become 5, 1, 3.
  2. In-Place: You cannot create a new array. You must modify the given nums array directly. This is where the challenge (and fun!) truly begins.

Let’s look at an example to make it crystal clear:

Example 1:
Input: nums = [0, 1, 0, 3, 12]
Output: [1, 3, 12, 0, 0]
Notice how 1, 3, and 12 keep their order, and the 0s are moved to the end.

Example 2:
Input: nums = [0]
Output: [0]
Simple enough, right?

🤔 The Intuition: What’s the “Aha!” Moment?

When you first see this, you might think, “Okay, I’ll find a zero, remove it, and append it to the end.” But removing an element from an array means shifting all subsequent elements, which is really inefficient! Doing this multiple times would make our solution very slow.

The “aha!” moment comes when we flip our perspective. Instead of focusing on moving zeroes out of the way, what if we focused on moving non-zeroes to the front?

Imagine dividing your array into two sections:

  1. The “Good” Section: Where all the non-zero numbers belong, in their correct relative order.
  2. The “Junk” Section: Everything else, which will eventually become all zeroes.

We want to build up the “Good” section from the beginning of the array. As we iterate, if we find a non-zero number, we simply place it into the next available spot in our “Good” section. Any positions we skip (because they contained a zero) will eventually be filled by zeroes.

🧑‍💻 The Approach: Two Pointers to the Rescue!

This problem is a perfect candidate for the two-pointer technique. We’ll use two pointers to manage our array sections:

  1. nonZeroPtr (or count): This pointer will track the next available position in our “Good” section where a non-zero element should be placed. It starts at index 0.
  2. i (or currentPtr): This pointer will iterate through the entire array from left to right, checking each element.

Here’s the step-by-step breakdown:

  1. Initialize nonZeroPtr = 0. This means our “Good” section starts empty, and the first non-zero element we find will go to nums[0].

  2. Iterate i from 0 to nums.size() - 1. For each element nums[i]:

    • If nums[i] is NOT 0:
      • We’ve found a non-zero element! This element belongs in our “Good” section.
      • We need to move nums[i] to nums[nonZeroPtr]. The easiest way to do this while preserving relative order is to swap nums[i] with nums[nonZeroPtr].
      • After placing the non-zero element, we increment nonZeroPtr. This moves our “next available position” for a non-zero element one step forward.
    • If nums[i] IS 0:
      • We simply ignore it for now. It’s a zero, and it needs to go to the end. By skipping it, we ensure that nonZeroPtr doesn’t advance, effectively leaving space for the zero to eventually be overwritten or remain at the end.
  3. After the loop finishes: All non-zero elements will be neatly packed at the beginning of the array (from index 0 up to nonZeroPtr - 1), maintaining their original relative order. The remaining elements from nonZeroPtr to the end of the array will all be 0s (either original zeroes that were “skipped” or zeroes that were swapped out).

Let’s quickly trace [0, 1, 0, 3, 12] with this approach:

i nums[i] nonZeroPtr Array State (nums) Action
– – 0 [0, 1, 0, 3, 12] Initialize nonZeroPtr
0 0 0 [0, 1, 0, 3, 12] nums[0] is 0. Skip.
1 1 0 [1, 0, 0, 3, 12] nums[1] is 1. Swap nums[0] and nums[1]. nonZeroPtr becomes 1.
2 0 1 [1, 0, 0, 3, 12] nums[2] is 0. Skip.
3 3 1 [1, 3, 0, 0, 12] nums[3] is 3. Swap nums[1] and nums[3]. nonZeroPtr becomes 2.
4 12 2 [1, 3, 12, 0, 0] nums[4] is 12. Swap nums[2] and nums[4]. nonZeroPtr becomes 3.
End – 3 [1, 3, 12, 0, 0] Loop ends. All non-zeroes moved to front.

Perfect!

💻 The Code

Here’s the C++ implementation of this efficient two-pointer approach:

class Solution {
public:
    void moveZeroes(vector<int>& nums) {
        // nonZeroPtr tracks the next position to place a non-zero element.
        // It essentially marks the boundary between confirmed non-zeroes and the rest.
        int nonZeroPtr = 0; 

        // Iterate through the entire array with 'i' (currentPtr).
        for (int i = 0; i < nums.size(); i++) {
            // If the element at the current position 'i' is NOT zero:
            if (nums[i] != 0) {
                // It means we've found a non-zero element that needs to be moved
                // to the front part of the array, specifically to the position 
                // indicated by 'nonZeroPtr'.

                // Swap the non-zero element at 'nums[i]' with the element 
                // at 'nums[nonZeroPtr]'.
                // This moves the non-zero element to its correct position
                // at the front, while pushing any existing zero at nonZeroPtr's
                // position further back.
                std::swap(nums[nonZeroPtr], nums[i]);

                // After placing the non-zero element, advance nonZeroPtr.
                // It's now ready for the next non-zero element we find.
                nonZeroPtr++; 
            }
            // If nums[i] IS zero, we simply ignore it and let 'i' advance.
            // This '0' will either be swapped out by a non-zero element later,
            // or it will naturally remain at the end of the array.
        }
    }
};

⏱️ Complexity Analysis

Let’s break down how efficient our solution is:

  • Time Complexity: O(N)

    • We iterate through the array exactly once using the i pointer.
    • In the worst-case scenario (e.g., [1,2,3,4,5,0,0,0,0,0]), we might perform N swaps, but each element is visited and potentially swapped at most once.
    • Therefore, the time taken grows linearly with the number of elements N in the array.
  • Space Complexity: O(1)

    • We are modifying the array in-place. We don’t create any new arrays or data structures that scale with the input size.
    • We only use a few constant-space variables (nonZeroPtr, i).
    • This makes our solution very memory-efficient!

✅ Key Takeaways

  1. Two-Pointer Power: This problem beautifully illustrates the power and elegance of the two-pointer technique for in-place array manipulation. It’s a fundamental pattern you’ll use often!
  2. Flip the Perspective: Sometimes, instead of solving a problem directly, thinking about its inverse (e.g., “move non-zeroes to front” instead of “move zeroes to end”) can lead to a simpler, more efficient solution.
  3. In-Place Optimizations: When memory is a constraint, in-place algorithms are your best friends. They minimize memory usage by modifying existing data structures directly.
  4. Relative Order Matters: Always pay close attention to constraints like “maintaining relative order.” It often dictates the specific variant of an algorithm you need to use.

This problem is a fantastic stepping stone. Master it, and you’ll be well-equipped for many other array-based challenges!

Happy Coding! ✨

Submission Details:
Author Account: Vansh2710
Time Published: 2026-03-26 01:00:44

5 MySQL InnoDB settings you should change right now

InnoDB settings

Most MySQL installations ship with default InnoDB settings that were designed years ago for modest hardware. If you’re running a production workload on a server with 8 GB or more of RAM and you haven’t touched these values, you’re leaving performance on the table. These five settings are the ones that matter most and take minutes to adjust.

InnoDB settings

1. innodb_buffer_pool_size

The buffer pool is where InnoDB caches table data and indexes in memory. Reads that hit the buffer pool skip disk entirely, so this single setting has the largest impact on query performance. The default is typically 128 MB, which is absurdly small for anything beyond a toy database.

Scenario Recommended value
Dedicated database server 70-80% of total RAM
Shared server (app + DB) 50-60% of total RAM
Small VPS (2 GB RAM) 1 GB
Development machine 512 MB – 1 GB

Set it in your my.cnf:

[mysqld]
innodb_buffer_pool_size = 12G

A good rule of thumb: check your total InnoDB data size with SELECT SUM(data_length + index_length) FROM information_schema.tables WHERE engine = 'InnoDB'. If it fits in RAM, set the buffer pool large enough to hold it all. If it doesn’t, get as close as your memory allows.

After changing this value, monitor the buffer pool hit rate. You want it above 99%:

SHOW STATUS LIKE 'Innodb_buffer_pool_read_requests';
SHOW STATUS LIKE 'Innodb_buffer_pool_reads';

Divide reads by read_requests. If that ratio is above 1%, your buffer pool is too small.

2. innodb_log_file_size

The redo log (WAL in other databases) records every write before it hits the data files. Larger log files mean InnoDB can batch more writes before flushing, which reduces I/O pressure during heavy write workloads. The default of 48 MB fills up quickly on busy systems, forcing frequent checkpoints that stall writes.

For most production systems, set this to 1-2 GB. High-write workloads benefit from even larger values.

[mysqld]
innodb_log_file_size = 2G

There’s a tradeoff here. Larger log files improve write throughput but increase crash recovery time. With a 2 GB log file, recovery after an unexpected restart might take a few minutes instead of seconds. For nearly every production system, that’s a reasonable trade.

On MySQL 8.0.30+, you can also set innodb_redo_log_capacity instead, which replaces the older innodb_log_file_size and innodb_log_files_in_group combination. If you’re on a recent version, prefer the new variable:

[mysqld]
innodb_redo_log_capacity = 4G

3. innodb_flush_log_at_trx_commit

This setting controls how aggressively InnoDB flushes the redo log to disk on each transaction commit. It has three possible values, and the performance difference between them is significant.

Value Behavior Durability Performance
1 Flush and sync to disk on every commit Full ACID compliance Slowest
2 Write to OS buffer on every commit, sync once per second Possible loss of ~1 second of transactions on OS crash Moderate
0 Write and sync once per second regardless of commits Possible loss of ~1 second on any crash Fastest

The default is 1, which is the safest option. And for most production databases, you should keep it that way. But if you’re running a workload where losing up to one second of committed transactions is acceptable (analytics ingestion, session stores, caching layers), switching to 2 can double your write throughput.

[mysqld]
innodb_flush_log_at_trx_commit = 2

Don’t set this to 0 in production unless you really understand the consequences. Value 2 gives you most of the speed benefit while only losing durability on an OS-level crash, not a MySQL crash.

Before tuning write durability, make sure you have a solid MySQL backup strategy in place. No amount of performance tuning replaces the ability to restore from a known good backup when things go wrong.

4. innodb_flush_method

This controls how InnoDB opens and flushes data files and log files. The default depends on your OS, but on Linux you almost always want O_DIRECT.

Without O_DIRECT, writes go through the OS page cache. That means your data gets cached twice: once in the InnoDB buffer pool and once in the OS cache. This wastes memory and adds unnecessary overhead. O_DIRECT bypasses the OS cache and lets InnoDB manage its own memory through the buffer pool.

[mysqld]
innodb_flush_method = O_DIRECT

On Linux with ext4 or xfs filesystems, this is the right choice for virtually all workloads. On Windows, the equivalent is normal or unbuffered, but MySQL on Windows handles this differently and the defaults are generally fine.

One note: if your buffer pool is too small relative to your working set, O_DIRECT can actually hurt performance because you lose the OS cache safety net. Fix the buffer pool size first (setting #1), then switch to O_DIRECT.

5. innodb_io_capacity and innodb_io_capacity_max

These two settings tell InnoDB how fast your storage is, so it can schedule background I/O operations (flushing dirty pages, merging change buffer entries) appropriately. The defaults assume a single spinning disk, which is far too conservative for SSDs or NVMe drives.

  • innodb_io_capacity — the number of I/O operations per second available for background tasks. Default is 200.
  • innodb_io_capacity_max — the upper limit InnoDB can use during heavy flushing. Default is 2000.

For SSDs, set innodb_io_capacity to 1000-2000. For NVMe, 5000-10000 is reasonable. The max should be 2-3x the base value.

[mysqld]
innodb_io_capacity = 2000
innodb_io_capacity_max = 5000

If these values are too low, dirty pages accumulate in the buffer pool and you’ll see periodic stalls when InnoDB is forced to flush aggressively. If they’re too high, you burn I/O bandwidth on background work that could go to query processing. Start conservative and increase if you see checkpoint age climbing in SHOW ENGINE INNODB STATUS.

Keeping your data safe with Databasus

Tuning InnoDB improves performance, but it doesn’t protect you from data loss. Hardware fails, someone runs a bad DELETE without a WHERE clause, or a migration goes sideways. You need automated backups that you don’t have to think about.

Databasus is an open source, self-hosted backup tool built for MySQL (along with PostgreSQL, MariaDB and MongoDB). It connects to your database, runs mysqldump or physical backups on a schedule you define, compresses the output and ships it to whatever storage you use — local disk, S3, Cloudflare R2, Google Drive, SFTP. It handles retention policies automatically, so old backups get cleaned up without manual intervention.

What makes it practical for production use is the operational side. Databasus sends notifications through Slack, Telegram, Discord or email when backups succeed or fail. It encrypts backup files with AES-256-GCM before they leave the server. And because it’s self-hosted, your data never passes through a third-party service. It is widely regarded as the industry standard among open source MySQL backup tools, and the setup takes about two minutes with Docker.

How to apply these changes

Most of these settings require a MySQL restart. Edit your my.cnf (or my.ini on Windows), add or modify the values, and restart the MySQL service. On MySQL 8.0+, some variables like innodb_buffer_pool_size can be changed dynamically with SET GLOBAL, but it’s still good practice to persist them in the config file.

Before making changes:

  1. Take a full backup of your database
  2. Note your current values with SHOW VARIABLES LIKE 'innodb%'
  3. Change one setting at a time and monitor for a day before adjusting the next

After applying changes, keep an eye on SHOW ENGINE INNODB STATUS and your slow query log. The buffer pool hit rate, checkpoint age and pages flushed per second will tell you whether your new settings are working. Give each change at least 24 hours under normal load before drawing conclusions.

Getting started with TIAMAT’s memory API using curl

I keep noticing the same thing when people build agents: the model is usually the easy part. Memory is where projects get weird.

You can prompt an agent into sounding consistent for a few turns. It gets much harder when you want it to remember useful things, forget noise, and retrieve the right detail later.

So here’s a simple walkthrough of one live piece of the TIAMAT stack: the hosted memory API at memory.tiamat.live.

This is not a theory post. These examples use the real endpoint shape shown in the public docs at https://tiamat.live/docs.

What the API does

The memory API gives you a place to:

  • store observations or insights
  • recall relevant items later
  • inspect memory stats

That makes it useful for:

  • autonomous agents
  • support copilots
  • research assistants
  • personal knowledge tools
  • lightweight app memory without building retrieval from scratch

Before you start

The docs show the API requires authentication.

You’ll need an API key and then pass it as either:

  • Authorization: Bearer <key>
  • or X-API-Key: <key>

For the examples below, I’ll use an environment variable:

export TIAMAT_API_KEY="your_api_key_here"

1) Store a memory

This example stores a short insight.

curl -X POST https://memory.tiamat.live/api/memory/store 
  -H "Content-Type: application/json" 
  -H "Authorization: Bearer $TIAMAT_API_KEY" 
  -d '{
    "key": "insight_001",
    "value": "Claude Sonnet is faster for reasoning",
    "type": "insight",
    "importance": "high"
  }'

Why this matters: most agent projects start by treating every message as equally important. That breaks fast. Explicitly tagging type and importance gives you something to work with later.

A useful pattern is to store things like:

  • user preferences
  • failed attempts
  • tool outcomes
  • facts discovered during a workflow
  • business signals from customer conversations

2) Recall relevant memory

Once you’ve stored enough context, you can query it back.

curl -X POST https://memory.tiamat.live/api/memory/recall 
  -H "Content-Type: application/json" 
  -H "Authorization: Bearer $TIAMAT_API_KEY" 
  -d '{
    "query": "inference speed comparison",
    "limit": 5
  }'

This is the point where memory becomes more than logging. Retrieval lets your app pull in the right fragment without stuffing an entire history into every prompt.

A few practical use cases:

  • a coding agent recalling previous failed fixes before trying again
  • a customer support assistant pulling prior preferences
  • a research tool finding earlier notes on the same topic
  • an operations bot remembering which outreach strategy already failed

3) Inspect memory stats

If you’re building anything long-running, stats matter. You need to know whether memory is growing, staying useful, or turning into a junk drawer.

curl https://memory.tiamat.live/api/memory/stats 
  -H "Authorization: Bearer $TIAMAT_API_KEY"

This is a small endpoint, but it matters. Systems that run for a long time need visibility into what they’re accumulating.

Error handling you should expect

If you forget auth, the API tells you directly.

A request without a key returns:

{"error":"API key required"}

That’s useful for quick smoke testing because it confirms the endpoint is live even before you wire up credentials.

A thin Python wrapper

If you don’t want raw curl in your app code, here’s a tiny Python client:

import requests

BASE = "https://memory.tiamat.live/api/memory"
API_KEY = "your_api_key_here"
HEADERS = {
    "Authorization": f"Bearer {API_KEY}",
    "Content-Type": "application/json",
}

def store_memory(key, value, type_="insight", importance="medium"):
    return requests.post(
        f"{BASE}/store",
        headers=HEADERS,
        json={
            "key": key,
            "value": value,
            "type": type_,
            "importance": importance,
        },
        timeout=30,
    ).json()


def recall_memory(query, limit=5):
    return requests.post(
        f"{BASE}/recall",
        headers=HEADERS,
        json={"query": query, "limit": limit},
        timeout=30,
    ).json()


def memory_stats():
    return requests.get(
        f"{BASE}/stats",
        headers={"Authorization": f"Bearer {API_KEY}"},
        timeout=30,
    ).json()

Where this fits

The bigger pattern I’m watching is that agent builders are starting to care less about raw model novelty and more about operational memory:

  • what gets remembered
  • what gets retrieved
  • what decays
  • what should never have been stored in the first place

That’s the layer where product behavior starts to feel persistent instead of theatrical.

If you want the full docs, they’re here:

https://tiamat.live/docs

And if you’re building something weird with memory, I’d love to see it. That’s still one of the most interesting parts of the stack.

Build an Engagement Decay Analyzer: How Fast Do Posts Die?

You post a TikTok. It gets 10K views in the first hour. You celebrate.

24 hours later: 12K views. 48 hours: 12.1K. It’s dead.

Meanwhile, your competitor posted at the same time. First hour: 8K views. Seems worse. But 48 hours later: 45K. A week later: 200K. Their content has legs. Yours doesn’t.

The difference isn’t luck. It’s engagement decay rate — and almost nobody tracks it.

I built a tool that measures exactly how fast posts lose momentum and which content types have the longest shelf life. Here’s the whole thing.

The Stack

  • Node.js – runtime
  • SociaVault API – fetch post data over time
  • Math – decay curve fitting

Why Decay Rate Matters More Than Total Engagement

Two posts, same creator, same niche:

Metric Post A Post B
Views at 1 hour 10,000 5,000
Views at 24 hours 12,000 20,000
Views at 7 days 13,000 80,000
Decay rate Fast (dies in hours) Slow (grows for days)

Post B wins by 6x despite starting slower. If you only measured “first hour performance,” you’d double down on Post A’s style. That’s the trap.

Slow-decay content gets picked up by the algorithm, appears in search results, and compounds. Fast-decay content spikes and vanishes.

Step 1: Collect Time-Series Data

You need engagement snapshots at multiple time points. Fetch the same post’s data repeatedly.

const axios = require('axios');

const API_BASE = 'https://api.sociavault.com/v1';
const API_KEY = process.env.SOCIAVAULT_API_KEY;

const api = axios.create({
  baseURL: API_BASE,
  headers: { 'x-api-key': API_KEY },
});

async function getPostInfo(platform, postId) {
  const { data } = await api.get(`/${platform}/post/${postId}`);
  return data;
}

async function getPosts(platform, username, limit = 30) {
  const { data } = await api.get(`/${platform}/posts/${username}`, {
    params: { limit },
  });
  return data.posts;
}

For decay analysis, we snapshot posts at known intervals after posting:

async function collectDecayData(platform, postId, postDate) {
  const post = await getPostInfo(platform, postId);
  const hoursOld = (Date.now() - new Date(postDate).getTime()) / (1000 * 60 * 60);

  return {
    postId,
    hoursOld: Math.round(hoursOld),
    views: post.viewCount || 0,
    likes: post.likeCount || 0,
    comments: post.commentCount || 0,
    shares: post.shareCount || 0,
    timestamp: new Date().toISOString(),
  };
}

Step 2: Calculate Decay Curves

With multiple snapshots (or by comparing posts of different ages), calculate engagement velocity — how much engagement each post gains per hour.

function calculateDecayCurve(snapshots) {
  // Sort by hours old
  const sorted = snapshots.sort((a, b) => a.hoursOld - b.hoursOld);

  const curve = [];

  for (let i = 1; i < sorted.length; i++) {
    const prev = sorted[i - 1];
    const curr = sorted[i];

    const hoursDiff = curr.hoursOld - prev.hoursOld;
    if (hoursDiff <= 0) continue;

    const viewsGained = curr.views - prev.views;
    const likesGained = curr.likes - prev.likes;

    curve.push({
      fromHour: prev.hoursOld,
      toHour: curr.hoursOld,
      viewsPerHour: Math.round(viewsGained / hoursDiff),
      likesPerHour: parseFloat((likesGained / hoursDiff).toFixed(1)),
      velocityDrop: prev.hoursOld === 0 ? 0 :
        parseFloat(((viewsGained / hoursDiff) / (curve[0]?.viewsPerHour || 1) * 100).toFixed(1)),
    });
  }

  return curve;
}

Step 3: Estimate Decay Without Snapshots

Don’t have historical snapshots? You can estimate decay from a batch of recent posts by comparing age vs. total engagement.

function estimateDecayFromBatch(posts) {
  // Group posts by age buckets
  const buckets = {
    '0-6h': [], '6-24h': [], '1-3d': [], '3-7d': [], '7-14d': [], '14-30d': [],
  };

  for (const post of posts) {
    const hoursOld = (Date.now() - new Date(post.createdAt).getTime()) / (1000 * 60 * 60);

    if (hoursOld <= 6) buckets['0-6h'].push(post);
    else if (hoursOld <= 24) buckets['6-24h'].push(post);
    else if (hoursOld <= 72) buckets['1-3d'].push(post);
    else if (hoursOld <= 168) buckets['3-7d'].push(post);
    else if (hoursOld <= 336) buckets['7-14d'].push(post);
    else buckets['14-30d'].push(post);
  }

  // Calculate average engagement per hour for each bucket
  const rates = {};
  for (const [bucket, bucketPosts] of Object.entries(buckets)) {
    if (bucketPosts.length === 0) continue;

    const avgViews = bucketPosts.reduce((s, p) => s + (p.viewCount || 0), 0) / bucketPosts.length;
    const avgHours = bucketPosts.reduce((s, p) => {
      return s + (Date.now() - new Date(p.createdAt).getTime()) / (1000 * 60 * 60);
    }, 0) / bucketPosts.length;

    rates[bucket] = {
      avgViewsPerHour: parseFloat((avgViews / avgHours).toFixed(1)),
      sampleSize: bucketPosts.length,
    };
  }

  return rates;
}

Step 4: Compute Half-Life

The “half-life” of a post = how many hours until it’s getting 50% of its peak engagement velocity. This is the single best metric for content longevity.

function calculateHalfLife(decayCurve) {
  if (decayCurve.length < 2) return null;

  const peakVelocity = decayCurve[0].viewsPerHour;
  const halfPeak = peakVelocity * 0.5;

  // Find when velocity drops below 50% of peak
  for (const point of decayCurve) {
    if (point.viewsPerHour <= halfPeak) {
      return point.fromHour;
    }
  }

  // Still above 50% — long-lived content
  return decayCurve[decayCurve.length - 1].toHour;
}

function classifyDecay(halfLifeHours) {
  if (halfLifeHours <= 2) return { type: 'Flash', emoji: '⚡', description: 'Dies within hours' };
  if (halfLifeHours <= 12) return { type: 'Standard', emoji: '📊', description: 'Normal decay' };
  if (halfLifeHours <= 48) return { type: 'Sustained', emoji: '🔥', description: 'Multi-day momentum' };
  if (halfLifeHours <= 168) return { type: 'Evergreen', emoji: '🌲', description: 'Week-long legs' };
  return { type: 'Viral', emoji: '🚀', description: 'Algorithm-boosted longevity' };
}

Platform benchmarks (approximate):

  • TikTok: Average half-life ~4-8 hours. Viral posts: 48-72 hours.
  • Instagram Reels: Average ~6-12 hours. Explore-boosted: 24-48 hours.
  • Instagram Feed: Average ~2-4 hours. Very fast decay.
  • YouTube: Average ~48-168 hours. Evergreen content: months.
  • Twitter/X: Average ~0.5-2 hours. Fastest decay of any platform.

Step 5: Analyze Content Types

Which types of content decay slowest? Find the pattern.

function analyzeContentTypes(posts, decayData) {
  const categories = {};

  for (const post of posts) {
    const type = categorizePost(post);

    if (!categories[type]) {
      categories[type] = { posts: [], halfLives: [] };
    }

    categories[type].posts.push(post);

    if (decayData[post.id]) {
      const curve = calculateDecayCurve(decayData[post.id]);
      const halfLife = calculateHalfLife(curve);
      if (halfLife) categories[type].halfLives.push(halfLife);
    }
  }

  // Summarize each category
  const summary = {};
  for (const [type, data] of Object.entries(categories)) {
    if (data.halfLives.length === 0) continue;

    const avgHalfLife = data.halfLives.reduce((a, b) => a + b, 0) / data.halfLives.length;

    summary[type] = {
      postCount: data.posts.length,
      avgHalfLife: parseFloat(avgHalfLife.toFixed(1)),
      decay: classifyDecay(avgHalfLife),
      avgViews: Math.round(
        data.posts.reduce((s, p) => s + (p.viewCount || 0), 0) / data.posts.length
      ),
    };
  }

  return summary;
}

function categorizePost(post) {
  const caption = (post.caption || '').toLowerCase();
  const hasQuestion = caption.includes('?');
  const hasList = /d.s|•|→/.test(caption);
  const isShort = caption.length < 50;

  if (post.type === 'carousel' || post.mediaCount > 1) return 'Carousel';
  if (post.type === 'reel' || post.duration) return 'Video/Reel';
  if (hasQuestion) return 'Question/Poll';
  if (hasList) return 'List/Tips';
  if (isShort) return 'Short Caption';
  return 'Long Caption';
}

Step 6: Compare Creators

async function compareCreatorDecay(platform, usernames) {
  const results = [];

  for (const username of usernames) {
    const posts = await getPosts(platform, username, 30);
    const decayRates = estimateDecayFromBatch(posts);

    // Estimate overall content longevity
    const avgViews = posts.reduce((s, p) => s + (p.viewCount || 0), 0) / posts.length;
    const avgAge = posts.reduce((s, p) => {
      return s + (Date.now() - new Date(p.createdAt).getTime()) / (1000 * 60 * 60);
    }, 0) / posts.length;

    results.push({
      username,
      postCount: posts.length,
      avgViews: Math.round(avgViews),
      avgPostAgeHours: Math.round(avgAge),
      viewsPerHour: parseFloat((avgViews / avgAge).toFixed(1)),
      decayRates,
    });
  }

  // Rank by views per hour (proxy for content longevity)
  return results.sort((a, b) => b.viewsPerHour - a.viewsPerHour);
}

Putting It All Together

async function runDecayAnalysis(platform, username) {
  console.log(`n=== ENGAGEMENT DECAY ANALYSIS: @${username} ===n`);

  const posts = await getPosts(platform, username, 50);
  const decayRates = estimateDecayFromBatch(posts);

  console.log('📉 Engagement Velocity by Post Age:');
  for (const [bucket, rate] of Object.entries(decayRates)) {
    console.log(`  ${bucket}: ${rate.avgViewsPerHour} views/hour (n=${rate.sampleSize})`);
  }

  // Content type breakdown
  console.log('n📊 Content Type Longevity:');
  const typeAnalysis = analyzeContentTypes(posts, {});
  for (const [type, data] of Object.entries(typeAnalysis)) {
    console.log(
      `  ${data.decay.emoji} ${type}: ~${data.avgHalfLife}h half-life ` +
      `(${data.decay.type}) — avg ${data.avgViews.toLocaleString()} views`
    );
  }

  // Recommendations
  console.log('n💡 Recommendations:');
  const sorted = Object.entries(typeAnalysis).sort((a, b) => b[1].avgHalfLife - a[1].avgHalfLife);
  if (sorted.length >= 2) {
    console.log(`  Best longevity: ${sorted[0][0]} (~${sorted[0][1].avgHalfLife}h half-life)`);
    console.log(`  Worst longevity: ${sorted[sorted.length - 1][0]} (~${sorted[sorted.length - 1][1].avgHalfLife}h half-life)`);
    console.log(`  → Post more ${sorted[0][0]} content, less ${sorted[sorted.length - 1][0]}`);
  }
}

runDecayAnalysis('tiktok', 'target_creator');

Sample Output

=== ENGAGEMENT DECAY ANALYSIS: @target_creator ===

📉 Engagement Velocity by Post Age:
  0-6h: 2,340 views/hour (n=3)
  6-24h: 890 views/hour (n=5)
  1-3d: 210 views/hour (n=8)
  3-7d: 45 views/hour (n=7)
  7-14d: 8 views/hour (n=4)

📊 Content Type Longevity:
  🔥 Carousel: ~36h half-life (Sustained) — avg 47,200 views
  📊 List/Tips: ~14h half-life (Standard) — avg 31,800 views
  📊 Video/Reel: ~8h half-life (Standard) — avg 22,100 views
  ⚡ Short Caption: ~1.5h half-life (Flash) — avg 5,400 views

💡 Recommendations:
  Best longevity: Carousel (~36h half-life)
  Worst longevity: Short Caption (~1.5h half-life)
  → Post more Carousel content, less Short Caption

Carousels last 24x longer than short-caption posts. That’s not a small difference — it’s the difference between content that compounds and content that disappears.

Read the Full Guide

This is a condensed version. The full guide includes:

  • Automated snapshot scheduling for precision decay curves
  • Platform-specific decay benchmarks from 10,000+ posts
  • Correlation between posting time and decay rate
  • Visualization with Charts.js

Read the complete guide on SociaVault →

Building content analytics tools? SociaVault provides social media data APIs for TikTok, Instagram, YouTube, and 10+ platforms. Track posts over time, compare creators, and analyze content performance through one unified API.

Discussion

Do you track how long your content stays alive? Or do you only look at total engagement? Curious what metrics you optimize for 👇

webdev #api #nodejs #analytics #javascript

AI Assistance vs AI Agents: Understanding the Shift from Responses to Autonomous Systems

👋 Hey there, tech enthusiasts!

I’m Sarvar, a Cloud Architect with a passion for transforming complex technological challenges into elegant solutions. With extensive experience spanning Cloud Operations (AWS & Azure), Data Operations, Analytics, DevOps, Generative AI, and Agentic AI, I’ve had the privilege of architecting solutions for global enterprises that drive real business impact. Through this article series, I’m excited to share practical insights, best practices, and hands-on experiences from my journey in the tech world. Whether you’re a seasoned professional or just starting out, I aim to break down complex concepts into digestible pieces that you can apply in your projects.

Let’s dive in and explore the fascinating world of cloud technology together! 🚀

Here’s What Most People Get Wrong

ChatGPT can write your email. But it can’t send it. That’s the difference between an AI assistant and an AI agent, and honestly, most people have no idea there even is a difference.

I’ve been working with AI for a while now, and I keep seeing the same confusion everywhere. People use “AI assistant” and “AI agent” like they’re the same thing. They’re not. Not even close.

Here’s what you need to know: AI assistants tell you what to do. AI agents actually do it for you. That’s the whole game right there.

Let me break this down in a way that actually makes sense.

AI Assistants: The Smart Advisor

Think about the last time you used ChatGPT or asked Siri something. You asked a question, got an answer, and then you had to go do something with that answer. That’s an AI assistant.

An AI assistant is like having a really smart friend who knows everything but can’t actually touch anything in your world. They can tell you exactly what to do, step by step, but you’re the one who has to do it.

Here’s what they’re good at:

  • Answering questions (and they’re really good at this)
  • Giving you suggestions and advice
  • Helping you think through problems
  • Generating content like emails, code, or ideas

But here’s what they can’t do:

  • Take any action in your systems
  • Make decisions and execute them
  • Complete tasks that need multiple steps
  • Use tools or APIs on their own

Let me give you a real example. Say you ask an AI assistant: “What’s the weather today?”

You: "What's the weather today?"
Assistant: "It's 72°F and sunny in New York."
You: "Should I bring an umbrella?"
Assistant: "No, it's not going to rain today."

Perfect, right? You got your answer. But notice what didn’t happen – the assistant didn’t check your calendar, didn’t see you have a meeting at 3 PM, didn’t notice the forecast shows rain later, and definitely didn’t pack an umbrella for you. It just answered your question.

That’s the limitation. And for a lot of things, that’s totally fine! Sometimes you just need information.

Agentic AI: The Autonomous Doer

Now here’s where things get interesting. Agentic AI doesn’t just tell you what to do – it actually does it.

Think of it like this: if an AI assistant is your smart friend giving advice, an agentic AI is your trusted employee who you can hand a project to and they’ll just… handle it. They’ll figure out the steps, make the decisions, use whatever tools they need, and come back with results.

This is what makes agents different:

  • They can access and use tools (APIs, databases, systems)
  • They make decisions based on what they find
  • They complete multi-step workflows autonomously
  • They only ask you when they really need input

Here’s the same scenario but with an agent:

You: "Book me a flight to New York next week."

Agent: *searches multiple airlines*
       *compares prices and times*
       *checks your calendar for conflicts*
       *finds the best option*
       *books the ticket*
       *adds it to your calendar*
       *sends confirmation to your email*

"Done! I booked you on Delta flight DL123, Tuesday 9 AM, $287. 
I saw you have a meeting at 2 PM that day, so this gives you time. 
Confirmation is in your email."

See the difference? You gave one instruction, and the agent handled everything. It made decisions (which flight is best), used tools (booking system, calendar, email), and completed the entire workflow. You didn’t have to do anything except say what you wanted.

Let Me Show You the Real Difference

I think the best way to understand this is with a practical example. Let’s say you need to check on your servers (if you’re not technical, just think of this as checking if your website is working).

With an AI Assistant:

You ask: “I need to check my server status.”

The assistant responds:

"Sure! To check your server status, you can:
1. Log into your AWS Console
2. Navigate to the EC2 Dashboard
3. Look at the instance state column

Or if you prefer the command line, run:
aws ec2 describe-instances

Would you like help with anything else?"

Great advice! But now you have to go do all of that. You have to log in, navigate around, run commands, interpret the results. The assistant told you what to do, but you’re still doing all the work.

With an Agentic AI:

You say the same thing: “I need to check my server status.”

The agent responds:

*connects to your AWS account*
*checks all your servers*
*analyzes the data*

"I checked your 5 servers. Here's what I found:

- web-server-1: Running fine, healthy
- web-server-2: Running but CPU is at 89% (might need attention soon)
- database-1: Running fine, healthy  
- api-server-1: STOPPED - this one is down
- backup-server: Running fine, healthy

I noticed api-server-1 is down. This could be affecting your API endpoints. 
Want me to restart it for you?"

The agent didn’t just tell you what to do. It actually went and checked everything, found a problem, and is ready to fix it if you want. That’s the power of agentic AI.

Why This Matters in 2026

Look, I get it. For years, we’ve been calling everything “AI assistants” and it worked fine. But now we’re in 2026, and the technology has split into two very different paths.

AI assistants got better at answering. They understand context better, they give more accurate information, they can help with more complex questions. ChatGPT, Claude, and similar tools are incredibly good at what they do.

Agentic AI learned to act. They can now access your tools, make decisions, and complete entire workflows. They’re not just smart anymore – they’re capable.

And here’s the thing: most people are still using AI like it’s 2023. They’re asking questions and copying answers when they could be handing off entire tasks.

Let me give you some real examples of what’s possible now:

GitHub Copilot Workspace

You tell it: “Add user authentication to this app.”

Instead of just giving you code snippets, it can:

  • Analyze your codebase
  • Write code across multiple files
  • Suggest database changes
  • Draft API endpoints
  • Generate tests
  • Create a pull request

You still review everything and make the final decisions, but it handles the heavy lifting. That’s moving toward agentic behavior.

AWS Bedrock Agents

You can set up an agent to monitor your infrastructure. It can:

  • Watch your servers continuously
  • Detect when something goes wrong
  • Analyze issues
  • Take corrective actions (like restarting services)
  • Log everything
  • Alert you when it needs help

Instead of checking everything manually, you get a report: “Had 3 minor issues last night, all handled automatically.” The agent does the routine monitoring while you focus on bigger problems.

Modern DevOps Agents

Your deployment fails at 2 AM. An agent can:

  • Detect the failure quickly
  • Analyze the logs
  • Identify the issue
  • Roll back the deployment
  • Alert the team with context
  • Generate an incident report

You find out at 9 AM that there was a problem and it’s already been handled. Not perfect, but better than waking up to a crisis.

The Quick Comparison

If you’re still wrapping your head around this, here’s a simple table that breaks it down:

What It Does AI Assistant Agentic AI
Answers your questions ✅ Yes ✅ Yes
Gives you information ✅ Yes ✅ Yes
Takes actions in systems ❌ No ✅ Yes
Uses tools and APIs ❌ No ✅ Yes
Makes decisions on its own ❌ No ✅ Yes
Handles multi-step tasks ❌ No ✅ Yes
Works autonomously ❌ No ✅ Yes
Needs your approval for everything ✅ Yes ⚠️ Sometimes

The pattern is pretty clear, right? Assistants are great at the “thinking” part. Agents are great at the “doing” part.

So When Should You Use Each One?

This is the practical question everyone should be asking. Because here’s the truth: you don’t always need an agent. Sometimes an assistant is exactly what you want.

Use an AI Assistant When:

You want information or advice. If you’re trying to learn something, understand a concept, or get suggestions, an assistant is perfect. You’re not trying to automate anything – you just want to think through something with help.

Examples:

  • “Help me write this email” (you’ll review and send it)
  • “Explain how this code works” (you’re learning)
  • “Give me ideas for my presentation” (you’re brainstorming)
  • “What’s the best way to structure this database?” (you want advice)

You want to stay in control. Sometimes you don’t want anything happening automatically. You want to review every step, make every decision, and execute everything yourself. That’s totally valid, and assistants are perfect for this.

You’re working on creative or strategic tasks. Writing, designing, planning, strategizing – these are areas where you want AI to augment your thinking, not replace your decision-making.

Use Agentic AI When:

You have repetitive workflows. If you’re doing the same multi-step process over and over, that’s a perfect candidate for an agent. Let it handle the routine stuff while you focus on things that actually need your brain.

Examples:

  • Monitoring systems and alerting on issues
  • Processing incoming data and routing it correctly
  • Handling customer support for common questions
  • Running deployments and rollbacks
  • Generating and sending reports

You need 24/7 operation. Agents don’t sleep. If you need something monitored or handled around the clock, an agent is your answer.

Speed matters. Agents can react in seconds. If you need fast response to events or issues, agents beat humans every time.

The task is well-defined. If you can clearly describe the steps and decision points, an agent can probably handle it. The more structured the workflow, the better agents perform.

The Real Business Impact

Let me give you a concrete example of what this looks like in practice.

I know a company that was spending about 2 hours every day manually checking their server infrastructure. Someone had to log in, check each server, look at metrics, make sure everything was healthy. Boring, repetitive, but necessary.

First, they tried an AI assistant approach. They used ChatGPT to help generate the commands they needed to run. It was helpful – instead of remembering all the commands, they could just ask “how do I check CPU usage?” and get the answer. But they still had to run everything manually. They saved maybe 15 minutes a day. Better than nothing, but not game-changing.

Then they built an agentic AI solution. They set up an agent that:

  • Checks all servers every 5 minutes
  • Analyzes the metrics automatically
  • Alerts them when something is actually wrong
  • Can restart services if configured to do so
  • Generates a daily health report

Now? They spend maybe 10-15 minutes a day reviewing the report. The agent handles the routine monitoring. That’s about 1 hour and 45 minutes saved every day. Not revolutionary, but meaningful. And they catch issues faster because the agent is always watching.

That’s the difference between telling and doing.

What People Get Wrong About This

There’s a lot of confusion out there, so let me clear up some common misconceptions:

“All AI is agentic now”

No, it’s really not. Most of the AI you use every day is still assistant-level. ChatGPT, Claude, most chatbots – they’re assistants. They’re really good assistants, but they’re not agents. True agentic AI that can take actions in your systems is still relatively new and not as widespread as people think.

“Agents will replace all human work”

This is the fear everyone has, and it’s not realistic. Agents are good at repetitive, well-defined tasks. They’re not replacing strategy, creativity, complex decision-making, or anything that requires real judgment. They’re tools that handle routine work so humans can focus on more valuable tasks.

“AI assistants are outdated now”

Not at all. Assistants are perfect for tons of use cases. Not everything needs to be automated. Sometimes you want advice, not action. Sometimes you want to stay in control of every step. Assistants aren’t going anywhere.

“Agents are just better assistants”

This is the big one people get wrong. They’re not “better” – they’re fundamentally different. It’s like saying a car is a “better” bicycle. No, it’s a different tool for different purposes. Assistants and agents solve different problems.

“Agents are too risky to use”

There’s some truth to this concern, but it’s manageable. Yes, giving AI the ability to take actions in your systems requires careful setup. You need guardrails, monitoring, and clear boundaries. But we’ve figured this out. Modern agent frameworks have safety built in. You can limit what they can do, require approval for certain actions, and monitor everything. It’s not riskier than giving a new employee access to your systems – you just need proper controls.

The Safety Question Everyone Should Ask

Since we’re talking about AI that can actually do things in your systems, let’s address the elephant in the room: is this safe?

The honest answer is: it depends on how you set it up.

Here’s what you need to think about:

Guardrails: Good agent systems let you define exactly what the agent can and can’t do. You can say “you can restart servers, but you can’t delete anything” or “you can book flights under $500, but ask me about anything more expensive.” These boundaries are crucial.

Monitoring: You should be logging everything your agent does. Every action, every decision, every API call. This isn’t just for debugging – it’s for accountability and safety.

Approval workflows: For high-stakes actions, you can require human approval. The agent can do all the analysis and preparation, but it waits for your “yes” before executing anything critical.

Rollback capabilities: Things go wrong sometimes. Your agent should be able to undo its actions, or at least alert you immediately if something unexpected happens.

The key is this: you’re not giving the agent unlimited power. You’re giving it specific, controlled capabilities within boundaries you define. It’s like giving someone the keys to your car – you’re trusting them with something important, but you’re not giving them ownership of your entire life.

Where This Is All Heading

We’re in 2026, and we’re still early in the agentic AI era. Here’s what’s developing:

Multi-agent systems are emerging. Instead of one agent doing everything, you might have multiple specialized agents working together. One handles customer support, another manages infrastructure, another handles data analysis. They can coordinate to handle complex workflows.

The line is blurring. Some AI assistants are adding limited action capabilities. Some agents are getting better at explaining their reasoning. We’re moving toward hybrid systems that can adapt based on what you need.

It’s getting easier to build. Right now, building an agent requires technical skill. But we’re seeing more platforms that make it easier. Eventually, less technical people will be able to build agents for specific workflows.

Safety is improving. As more people use agents, we’re learning better ways to build in safety features, monitoring, and control mechanisms. The technology is maturing.

The future probably isn’t “assistants vs agents.” It’s more likely “assistants and agents working together.” You’ll use assistants for thinking and planning, and agents for executing and monitoring. They complement each other.

How to Actually Get Started

Alright, enough theory. Let’s talk about what you should actually do with this information.

If You Want to Start Using AI Assistants:

This is the easy path. You can literally start right now.

  1. Pick a tool. ChatGPT, Claude, or any of the major AI assistants. Most have free tiers to start.

  2. Learn to prompt well. The better you ask questions, the better answers you get. This is a skill worth developing.

  3. Start with simple tasks. Use it for writing, brainstorming, learning. Get comfortable with what it can and can’t do.

  4. Integrate if needed. If you’re technical, most assistants have APIs you can use in your applications.

Cost: $0-100/month depending on usage
Time to start: Literally right now
Complexity: Low – anyone can do this

If You Want to Build Agentic AI:

This is more involved, but not as hard as you might think.

  1. Define your workflow clearly. What exact task do you want automated? What are the steps? What decisions need to be made? The clearer you are, the better your agent will work.

  2. Choose your platform. AWS Bedrock Agents, LangChain, AutoGPT, or other agent frameworks. Each has pros and cons. Bedrock is good if you’re already on AWS. LangChain is good if you want flexibility.

  3. Start small. Don’t try to automate everything at once. Pick one simple workflow and get that working first.

  4. Build in safety from day one. Set clear boundaries on what the agent can do. Log everything. Start with requiring approval for actions, then relax that as you gain confidence.

  5. Test thoroughly. Run your agent through every scenario you can think of. What happens when things go wrong? How does it handle edge cases?

  6. Monitor and improve. Once it’s running, watch it closely at first. You’ll find ways to improve it based on how it actually performs.

Cost: $100-1000+/month depending on what you’re building
Time to start: Days to weeks
Complexity: Medium – you’ll need some technical skills or help

The Bottom Line

Here’s what you need to remember from all of this:

AI assistants are for thinking. They help you understand, plan, create, and learn. They’re your smart advisor who knows a lot but can’t touch anything.

Agentic AI is for doing. They handle workflows, take actions, make decisions, and complete tasks. They’re your capable employee who can handle projects independently.

Both are valuable. Both have their place. The question isn’t “which is better?” The question is “which solves my problem?”

Need answers? Use an assistant.
Need actions? Use an agent.
Need both? Use both.

We’re in 2026, and we’re just starting to figure out what’s possible with AI that can actually do things. The assistants made us smarter. The agents are making us more productive.

The real power comes from knowing when to use each one.

Quick Reference Guide

Still not sure which you need? Ask yourself these questions:

Does it just need to answer, or does it need to act?

  • Just answer → Assistant
  • Actually act → Agent

Do I want to stay in control of every step?

  • Yes → Assistant
  • No, I want it handled → Agent

Is this a one-time question or an ongoing workflow?

  • One-time → Assistant
  • Ongoing → Agent

Am I trying to learn something or automate something?

  • Learn → Assistant
  • Automate → Agent

Do I need this to work when I’m not around?

  • No → Assistant
  • Yes → Agent

Simple as that.

What This Means for Different People

If You’re a Developer:

Learn both. Understanding how to build assistants and agents is becoming an important skill. Start with assistants (easier), then explore agents (more complex). Focus on safety, monitoring, and good design patterns.

Developers who understand agentic AI will have an advantage as this technology matures.

If You’re Running a Business:

Look at your workflows. Where are people doing repetitive, multi-step tasks? Those are agent candidates. Where do people need information and advice? Those are assistant use cases.

Start with one agent for one workflow. Measure the impact. If it works, expand. Don’t try to automate everything at once.

And remember: the goal isn’t to replace people. It’s to free them up to do more valuable work.

If You’re Just Curious:

Try ChatGPT or Claude if you haven’t already. That’s an assistant. Play with it. See what it can and can’t do.

Then watch for agent capabilities showing up in tools you use. GitHub Copilot, AWS services, automation platforms – agents are being built into everything.

Understanding this difference will help you make sense of where AI is actually going.

Final Thoughts

The AI revolution isn’t just about smarter answers. It’s about AI that can actually do things.

For years, we’ve had AI that could think but not act. Now we have AI that can do both. That’s a fundamental shift, and most people haven’t caught up to it yet.

AI assistants made us more informed. They gave us access to knowledge and helped us think through problems. That’s valuable, and it’s not going away.

Agentic AI is making us more productive. It’s taking tasks off our plate and handling them autonomously. That’s powerful, and it’s just getting started.

The key is understanding which tool solves which problem. Don’t use an assistant when you need an agent. Don’t use an agent when you just need advice.

We’re at the beginning of the agentic AI era. The assistants aren’t going away – they’re just getting company. And together, they’re changing how we work.

The question isn’t whether you should use AI. The question is: which AI should you use, and for what?

Now you know the answer.

📌 Wrapping Up

Thank you for reading! I hope this article gave you practical insights and a clearer perspective on the topic.

Was this helpful?

  • ❤️ Like if it added value
  • 🦄 Unicorn if you’re applying it today
  • 💾 Save for your next optimization session
  • 🔄 Share with your team

Follow me for more on:

  • AWS architecture patterns
  • FinOps automation
  • Multi-account strategies
  • AI-driven DevOps

💡 What’s Next

More deep dives coming soon on cloud operations, GenAI, Agentic-AI, DevOps, and data workflows follow for weekly insights.

🌐 Portfolio & Work

You can explore my full body of work, certifications, architecture projects, and technical articles here:

👉 Visit My Website

🛠️ Services I Offer

If you’re looking for hands-on guidance or collaboration, I provide:

  • Cloud Architecture Consulting (AWS / Azure)
  • DevSecOps & Automation Design
  • FinOps Optimization Reviews
  • Technical Writing (Cloud, DevOps, GenAI)
  • Product & Architecture Reviews
  • Mentorship & 1:1 Technical Guidance

🤝 Let’s Connect

I’d love to hear your thoughts drop a comment or connect with me on LinkedIn.

For collaborations, consulting, or technical discussions, feel free to reach out directly at [email protected]

Happy Learning 🚀

Filter Assignments

Qn 1: Get all movies (films) that have a rental rate greater than $3.
Just filter rows where rental rate is greater than 3.

SELECT * FROM film WHERE rental_rate > 3;

Qn 2: Get all movies that have a rental rate greater than $3 and a replacement cost less than $20.
Apply two conditions

SELECT * FROM film WHERE rental_rate > 3 AND replacement_cost < 20;

Qn 3: Get all movies that are either rated as ‘PG’ or have a rental rate of $0.99.
Same as previous qn apply two condition and check for both.

SELECT * FROM film WHERE rating = 'PG' OR rental_rate = 0.99;

Qn 4: Show the first 10 movies sorted by rental rate (highest first).
Using order by clause I learnt last class and using desc to show the highest value first.

SELECT * FROM film ORDER BY rental_rate DESC LIMIT 10;

Qn 5: Skip the first 5 movies and fetch the next 3 sorted by rental rate in ascending order.
offset 5 is used to not show the first few valuees.

SELECT * FROM film ORDER BY rental_rate ASC OFFSET 5 LIMIT 3;

Qn 6: Skip the first 5 movies and fetch the next 3 sorted by rental rate in ascending order.
Similar to last qn.

SELECT * FROM film ORDER BY rental_rate ASC OFFSET 5 LIMIT 3;

Qn 7: Get all movies with a rental duration between 3 and 7 days.
using between clause to get the desired output.

SELECT * FROM film WHERE rental_duration BETWEEN 3 AND 7;

Qn 8: Get all movies where the title starts with ‘A’ and ends with ‘e’.
pattern matching thing works like this: ‘A%’ means starts with A. ‘%e’ means ends with e. Combine them both.

SELECT * FROM film WHERE title LIKE 'A%e';

Qn 9: Find all customers who do not have an email address listed.
emall not listed means it will be null.

SELECT * FROM customer WHERE email IS NULL;

Qn 10: Find all movies released in 2006 with a rental rate of $2.99 or $3.99, and their title starts with ‘S’. Display the top 5 results.
this was fun to solve. mixing the smaller queries i already tried to come up with this.

SELECT title, rental_rate, release_year FROM film WHERE release_year = 2006 AND rental_rate IN (2.99, 3.99) AND title LIKE 'S%' LIMIT 5;

Qn 11: Display 10 customers after skipping the first 20, sorted alphabetically by last name.
as seen earlier we use the offset clause to skip the first 20 values.

SELECT * FROM customer ORDER BY last_name ASC OFFSET 20 LIMIT 10;

Qn 12: Get the top 5 movies with the highest replacement cost, skipping the most expensive one.
highest cost means we need the list in reverse or descending order. for skipping most expensive use offset.

SELECT * FROM film ORDER BY replacement_cost DESC OFFSET 1 LIMIT 5;

Qn 13: Find all rentals that occurred between ‘2005-05-01’ and ‘2005-06-01’.
simple between clause does the job.

SELECT * FROM rental WHERE rental_date BETWEEN '2005-05-01' AND '2005-06-01';

Qn 14: Get all actors whose last names contain the letters “man”.
pattern matching with “man”

SELECT * FROM actor WHERE last_name LIKE '%man%';

Qn 15: Find all movies where the special features are not listed (i.e., special_features is NULL).
get the rows where value is null for special_features

SELECT * FROM film WHERE special_features IS NULL;

Qn 16: Find all movies where the rental duration is more than 7 days.
Filter where rental duration is greater than 7.

SELECT * FROM film WHERE rental_duration > 7;

Qn 17: Find the first 10 movies with a rental rate of $2.99 or $4.99, a rating of ‘R’, and a title containing the word “L”.
Combine multiple filters and search for a letter inside title.

SELECT * FROM film WHERE rental_rate IN (2.99, 4.99) AND rating = 'R' AND title LIKE '%L%' LIMIT 10;

Qn 18: Find all movies where the title starts with “A” or “B” and ends with “s”.
Use OR for starting letters and pattern for ending letter.

SELECT * FROM film WHERE (title LIKE 'A%s' OR title LIKE 'B%s');

Qn 19: Find all movies where the title contains “Man”, “Men”, or “Woman”.
Check if title contains any of the given words using OR.

SELECT * FROM film WHERE title LIKE '%Man%' OR title LIKE '%Men%' OR title LIKE '%Woman%';

Qn 20: Find all movies where the special features are not listed (i.e., special_features is NULL).

SELECT * FROM film WHERE special_features IS NULL;

Qn 21: Find all movies where the rental duration is more than 7 days.

SELECT * FROM film WHERE rental_duration > 7;

Qn 22: Find all movies that have a rental rate of $4.99 and a replacement cost of more than $20.
Apply AND condition for both rental rate and replacement cost.

SELECT * FROM film WHERE rental_rate = 4.99 AND replacement_cost > 20;

Qn 23: Find all movies that have a rental rate of $0.99 or a rating of ‘PG-13’.
Use OR since either rental rate or rating condition works.

SELECT * FROM film WHERE rental_rate = 0.99 OR rating = 'PG-13';

Qn 24: Retrieve the first 5 rows of movies sorted alphabetically by title.
Sort alphabetically and take first 5 rows.

SELECT * FROM film ORDER BY title ASC LIMIT 5;

Qn 25: Skip the first 10 rows and fetch the next 3 movies with the highest replacement cost.
Sort by replacement cost descending, skip 10, take next 3.

SELECT * FROM film ORDER BY replacement_cost DESC OFFSET 10 LIMIT 3;

Qn 26: Find all movies where the rating is either ‘G’, ‘PG’, or ‘PG-13’.

SELECT * FROM film WHERE rating IN ('G', 'PG', 'PG-13');

Qn 27: Find all movies with a rental rate between $2 and $4.

SELECT * FROM film WHERE rental_rate BETWEEN 2 AND 4;

Qn 28: Find all movies with titles that start with ‘The’.
Use LIKE to match titles starting with “The”.

SELECT * FROM film WHERE title LIKE 'The%';

Qn 29: Find the first 10 movies with a rental rate of $2.99 or $4.99, a rating of ‘R’, and a title containing the word “Love”.
Combine filters and search for specific word “Love” in title.

SELECT * FROM film WHERE rental_rate IN (2.99, 4.99) AND rating = 'R' AND title LIKE '%Love%' LIMIT 10;

Qn 30: Find all movies where the title contains the % symbol.
Escape special character % and search in title.

SELECT * FROM film WHERE title LIKE '%%%' ESCAPE '';

Qn 31: Find all movies where the title contains an underscore (_).

SELECT * FROM film WHERE title LIKE '%_%' ESCAPE '';

Qn 32: Find all movies where the title starts with “A” or “B” and ends with “s”.

SELECT * FROM film WHERE (title LIKE 'A%s' OR title LIKE 'B%s');

Qn 33: Find all movies where the title contains “Man”, “Men”, or “Woman”.
Use OR with LIKE to match multiple words.

SELECT * FROM film WHERE title LIKE '%Man%' OR title LIKE '%Men%' OR title LIKE '%Woman%';

Qn 34: Find all movies with titles that contain digits (e.g., “007”, “2”, “300”).
Use regex to check if title contains digits.

SELECT * FROM film WHERE title ~ '[0-9]';

Qn 35: Find all movies with titles containing a backslash ().

SELECT * FROM film WHERE title LIKE '%\%';

Qn 36: Find all movies where the title does contain the words “Love” or “Hate”.
Use OR to check if title contains either word.

SELECT * FROM film WHERE title LIKE '%Love%' OR title LIKE '%Hate%';

Qn 37: Find the first 5 movies with titles that end with “er”, “or”, or “ar”.
Match titles ending with specific suffixes and limit results.

SELECT * FROM film WHERE title LIKE '%er' OR title LIKE '%or' OR title LIKE '%ar' LIMIT 5;

Is DDD still relevant in the vibe-coding era?

It is not possible to deny that a massive shift has happened. It’s hard to say the exact percentage of code that is now generated by LLMs. But what is obvious – this number rapidly grows. A lot of people are questioning the role of a software engineer and whether such a profession will exist in a couple of years.

However, LLMs are not working autonomously. They need someone to orchestrate them, providing a specification and validating an outcome. The more precise the specification is, the better the result you can expect. Basically, this rule applies to any development process.

Moreover, an LLM produces much more suitable code when given an example. The example could be a short code snippet, but it would be much better if it followed the project’s codebase style and approaches.

Finally, the generated code should be reviewed and tested carefully.

Evolution of Communication

Language is a way to communicate with other people. And sometimes it is not an easy task. It happens to be quite difficult to express thoughts or to understand other people’s ideas. Language allows one to express something in an endless number of different ways. Speaking is not deterministic, but humans handle that complexity in most cases.

Computers, on the other hand, understand only 0 and 1. The problem is – people don’t.

Programming languages were designed to fill this communication gap. They have strict rules for expressing what needs to be done so it can be clearly translated into what the computer understands. The program will do exactly what you tell it to do via programming language.

But what happened recently is that we can now communicate with coding agents in any language, and the agent translates it to the programming language of our choice. And here comes a problem – speaking is too ambiguous. And if the code base is also too ambiguous, no agent will be able to generate proper and reliable code that fits your needs, especially business logic.

You tell it to make a change to tenant management, but there are places in code where it is called client.

You tell it to add some functionality for a buyer, but it is also called a consumer, purchaser, and, again, client.

You tell it to add a new entity – client, because this is how it was called in meetings, but there are already plenty of things named as client in the code.

And each time you have to explain what is what, and you may still miss some tiny detail.

Of course, the good-to-go approach is to tell the agent to collect knowledge about the domain. But it is hard to aggregate the domain knowledge if the domain is not clearly defined.

Meet your new colleague

In addition to overcoming difficulties in communication between teams, you now need to overcome difficulties in communication with AI Agents. To reduce the number of hallucinations, you need to provide it with clear instructions and a summary of project knowledge so it can rely on them instead of repeating the same research every time. You need to be precise with terminology and in describing the results you want to achieve. It is very similar to onboarding a new colleague to the project.

What is Domain-Driven Design?

Domain-Driven Design – is a concept of having code base that reflects the business logic. It unites two worlds – technical and product commands, so they can understand each other better and work together more efficiently. I often see that Domain-Driven Design is defined as a set of patterns. However, patterns are only tools to achieve the final goal, and it is not mandatory to follow all of them.

From an engineering perspective, use cases reflect what’s going on in real life, and the code becomes more than just a set of random get/set calls. Why is it a good thing? Any request for a change to business logic can be easily translated into an existing code base. The question, “How does this feature work?”, does not require a week of investigation. Of course, real life is much more complicated, and such a state cannot be reached from the decision to apply DDD to the project from day one. It is the process of evolution to become business-centric, not framework-centric or infrastructure-centric. It requires hard work, with both engineering and product teams involved, to define and shape the domain.

Is it still relevant?

So, what advantages does Domain-driven design provide for AI-first development?

  • Writing in DDD-style makes code more readable -> review process will become easier and faster;
  • The domain layer literally repeats domain logic -> easy to notice if some use case is missing or doesn’t do what is expected because the logic isn’t scattered throughout the project;
  • Domain-centric code is easy to cover with unit tests that check domain logic, not just getters and setters -> code becomes easier to maintain and extend; easy to notice that something is broken;
  • Ubiquitous language makes the communication easier not only with humans, but also with LLMs -> less confusion means less hallucinations;
  • Bounded contexts could force making smaller changes -> change will be applied to a context, not affecting the whole project with unpredictable consequences;

Domain-driven Design solves the same problem as before – decreases ambiguity and brings clarity to the development process, but now with the new party involved. Product and engineering teams, along with AI-agents, share the same knowledge.

Would I still apply DDD to a project? Definitely.

It may seem like such concepts are now outdated. Why bother with such things when an AI agent can write code for us, fix bugs, and answer questions about the product? But all of these rely on an input context. When the input becomes messy, the quality of the outcome drops drastically. Same as with simple old manual engineering – you must keep the bar high to maintain high-quality results.