Why Record Mistakes

In the previous post, I introduced the content seed system. Prompts, ideas, and misses. The category for recording mistakes.

Why record mistakes?

First, to avoid repeating them. If you don’t record, you forget. And three months later, you struggle with the same thing.

Second, it helps others. Someone else can avoid the path I stumbled on.

Third, failure itself is good content. Failure stories teach more than success stories. They’re specific, practical, and relatable.

Here are three mistakes I made while building this blog.

I cloned the Hugo blog and ran hugo server. It worked. But posts weren’t showing up.

Checked the content/posts/ directory. No files. Strange. I definitely set this up before.

Turns out content/posts was a symlink:

ls -la content/posts
# lrwxr-xr-x  content/posts -> /Users/deok/brainFucked/10-Blog/published

See the problem? Current user is koed, but the symlink points to /Users/deok/. The path from my old Mac was still there.

Why this happened:

  • Copied dotfiles when setting up new Mac
  • Cloned the git repo
  • Symlink’s absolute path remained
  • No error message - just looks like an empty directory

Solution:

rm content/posts
ln -s /Users/koed/Dev/BrainFucked/10-Blog/published content/posts

Lessons:

  1. Use relative path symlinks when possible
  2. After copying dotfiles to a new machine, check absolute paths
  3. “Nothing there” can be an error

Mistake 2: Bash’s Hidden Behavior

Made a test script. Counter increments when first test passes. But the script exits right after the first test. No error message.

#!/bin/bash
set -e  # Exit immediately on error
TESTS_PASSED=0

log_success() {
    echo "[PASS] $1"
    ((TESTS_PASSED++))  # Script dies here!
}

log_success "First test"  # Only this prints, then exits
log_success "Second test" # Never reaches here

What happened:

((TESTS_PASSED++)) is an arithmetic expression. Its return value is the value before increment, not after.

  • When TESTS_PASSED is 0
  • ((TESTS_PASSED++)) returns 0
  • In Bash, 0 is falsy
  • Because of set -e, falsy return value → script exits

The irony of dying on first success.

Solution:

log_success() {
    echo "[PASS] $1"
    TESTS_PASSED=$((TESTS_PASSED + 1))  # This is safe
}

Lessons:

  1. set -e and ((var++)) combination is dangerous
  2. Silent exits without errors are hardest to debug
  3. Know the return values of Bash arithmetic operators

Mistake 3: Where to Put API Keys

Setting up OpenCode required an API key. First instinct was to put it in ~/.zshrc:

export GEMINI_API_KEY="sk-..."

But something felt off.

“putting api in shell config seems not good”

Right. There are problems:

  • Key is exposed to all shell processes
  • Could end up in history
  • If dotfiles are git-managed, might accidentally commit

Better approach - macOS Keychain wrapper:

#!/bin/bash
# ~/bin/openclaw - wrapper script

fetch_key() {
    local keychain_name="$1"
    security find-generic-password -a "$USER" -s "$keychain_name" -w 2>/dev/null || {
        echo "Error: $keychain_name not found in Keychain" >&2
        return 1
    }
}

export GEMINI_API_KEY=$(fetch_key "gemini-api-key") || exit 1

exec /path/to/actual/command "$@"

This way:

  • Key is stored securely in Keychain
  • Key is loaded into environment variable only during command execution
  • Key disappears after command exits
  • Not exposed to other processes
MethodKey Exposure Scope
~/.zshrc exportAll shells, all processes
Wrapper scriptOnly during that command’s execution

Lessons:

  1. Don’t put API keys in shell config files
  2. macOS Keychain is easier to use than you think
  3. The wrapper script pattern is universally useful

Why Record These Things

These three mistakes have something in common.

  1. Hard to find: No error messages or they’re vague
  2. Common: I’m not the only one who experiences them
  3. Forgotten if not recorded: I’ll struggle again in three months

That’s why I created the misses/ category in the content seed system. Record every mistake. Whether it becomes a blog post later or just personal reference.

To learn from failure, you must record failure.

Next Up

While organizing these mistakes, I discovered an interesting pattern. The process of building this blog was becoming blog content itself. Working while recording, and those records becoming content again.

In the next post, I’ll talk about the interesting pattern discovered through all of this.


All the mistakes in this post actually happened and were first recorded as misses/ seeds.


Series So Far

  1. Building a Blog with AI: The Beginning
  2. Learning from Failure: The Value of Small Mistakes
  3. Content Begets Content: Discovering Meta-Recursion

More to come…