Skip to content

Commit 277456b

Browse files
Oliver Baerclaude
andcommitted
chore(memory): session handoff
- Added letter_04.md documenting blog_gen.py fixes - Model ID update and numeric file sorting Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
1 parent d1b2eb4 commit 277456b

2 files changed

Lines changed: 172 additions & 0 deletions

File tree

.memory/letter_04.md

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
# Letter to Myself (Session Handoff)
2+
3+
**Date:** 2026-01-30 13:15
4+
5+
## 1. Executive Summary
6+
* **Goal:** Fix Vibe Coding blog generation pipeline failures in GitHub Actions
7+
* **Current Status:** Complete — two bugs fixed and pushed, awaiting workflow re-run
8+
9+
## 2. The "Done" List (Context Anchor)
10+
* Configured global Anthropic API key at `~/.config/letter-for-my-future-self/config.json`
11+
* Fixed outdated model ID in `.github/scripts/blog_gen.py` (line 216)
12+
- Changed from `claude-3-5-sonnet-20241022` to `claude-sonnet-4-20250514`
13+
* Fixed file sorting bug in `get_latest_memory_file()` function (lines 157-179)
14+
- Was: alphabetic sort (`letter_example.md` > `letter_03.md`)
15+
- Now: numeric sort using regex to match `letter_XX.md` pattern only
16+
* Pushed commits: ea81c8a (model fix), d1b2eb4 (sorting fix)
17+
18+
## 3. The "Pain" Log (CRITICAL)
19+
* **Tried:** Using model `claude-3-5-sonnet-20241022`
20+
* **Failed:** `anthropic.NotFoundError: 404 - model: claude-3-5-sonnet-20241022`
21+
* **Workaround:** Updated to current model `claude-sonnet-4-20250514`
22+
* *Note:* Model IDs change over time — consider using model aliases if Anthropic provides them
23+
24+
* **Tried:** Alphabetic sorting of letter files with `sorted(..., reverse=True)`
25+
* **Failed:** `letter_example.md` selected instead of `letter_03.md` (alphabetic: 'e' > '0')
26+
* **Workaround:** Added regex matching for `letter_(\d+)\.md` pattern with numeric sorting
27+
28+
## 4. Active Variable State
29+
* Global API key: `~/.config/letter-for-my-future-self/config.json` (ends with `...HwAA`)
30+
* GitHub secret: `ANTHROPIC_API_KEY` configured in repo settings
31+
* Current branch: `main` at commit `d1b2eb4`
32+
* Workflow: `vibe_publisher.yml` should auto-trigger on .memory/ changes
33+
34+
## 5. Immediate Next Steps
35+
1. [ ] Monitor GitHub Actions for successful blog generation
36+
2. [ ] Review generated PR in `drafts/` directory
37+
3. [ ] Consider adding model ID as configurable option in blog_gen.py
38+
4. [ ] Fix setup-api-key.sh non-interactive TTY issue (from letter_03)
Lines changed: 134 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,134 @@
1+
---
2+
title: "When Setup Scripts Meet Reality: A Tale of TTY and API Keys"
3+
date: 2026-01-30
4+
tags: [api-keys, automation, bash, devops, debugging]
5+
excerpt: "What happens when your perfectly crafted setup script meets the harsh reality of non-interactive environments? A debugging journey through TTY detection and API key configuration."
6+
---
7+
8+
# When Setup Scripts Meet Reality: A Tale of TTY and API Keys
9+
10+
Every developer has been there: you craft what seems like the perfect setup script, test it locally, and everything works beautifully. Then you deploy it to the real world, and suddenly your users are staring at broken installations with no clear explanation. Today, I'm sharing one of those humbling moments from my work on the Vibe Coding blog generation pipeline.
11+
12+
## The Mission: Streamline API Key Configuration
13+
14+
I was working on integrating Anthropic's Claude API into our automated blog generation system. The goal was simple: make the installation process seamless by automatically prompting users for their API key during plugin installation. What could go wrong?
15+
16+
## The Perfect Plan (That Wasn't)
17+
18+
My setup script looked elegant in its simplicity:
19+
20+
```bash
21+
# setup-api-key.sh
22+
if [ -t 0 ]; then
23+
echo "Setting up Anthropic API key..."
24+
read -p "Enter your API key: " api_key
25+
# ... save to config
26+
else
27+
echo "Non-interactive mode detected, skipping setup"
28+
fi
29+
```
30+
31+
The TTY check (`[ -t 0 ]`) seemed like the right approach—detect if we're running interactively and prompt accordingly. During local testing, everything worked flawlessly.
32+
33+
## Reality Strikes: The Non-Interactive Wall
34+
35+
When users started installing the plugin via `claude plugin install`, something strange happened. The setup hook would run, but users never saw the API key prompt. The script would silently skip the interactive setup, leaving users with a half-configured system.
36+
37+
The culprit? **Plugin installation hooks run in non-interactive mode by default.**
38+
39+
Even though users were running the install command from their terminal, the hook execution environment didn't have a TTY attached. My clever TTY detection was working exactly as designed—it was just detecting the wrong thing.
40+
41+
## The Debugging Journey
42+
43+
Here's what the investigation looked like:
44+
45+
```bash
46+
# Testing the current status
47+
$ python3 blog_gen.py --status
48+
❌ API key not configured
49+
50+
# Checking the config location
51+
$ ls ~/.config/letter-for-my-future-self/
52+
# (directory didn't exist)
53+
54+
# The moment of realization
55+
$ echo "test" | ./scripts/setup-api-key.sh
56+
# Non-interactive mode detected, skipping setup
57+
```
58+
59+
The script was behaving correctly according to its logic, but the user experience was broken. Users had no clear path forward after installation.
60+
61+
## The Fix: Manual Configuration with a Plan
62+
63+
For the immediate problem, I configured the API key manually:
64+
65+
```bash
66+
# Create the config directory
67+
mkdir -p ~/.config/letter-for-my-future-self
68+
69+
# Write the configuration
70+
cat > ~/.config/letter-for-my-future-self/config.json << EOF
71+
{
72+
"anthropic_api_key": "sk-ant-api03-[YOUR_KEY_HERE]"
73+
}
74+
EOF
75+
76+
# Secure the config file
77+
chmod 600 ~/.config/letter-for-my-future-self/config.json
78+
```
79+
80+
Then verified it worked:
81+
82+
```bash
83+
$ python3 blog_gen.py --status
84+
✅ API key configured (ends with: ...HwAA)
85+
✅ Blog generation ready
86+
```
87+
88+
Success! But this was clearly a band-aid solution.
89+
90+
## Lessons Learned: Better UX for Non-Interactive Installs
91+
92+
This experience highlighted several key insights about building robust installation experiences:
93+
94+
### 1. **Assume Non-Interactive by Default**
95+
Plugin hooks, CI/CD pipelines, and automated deployments often run without TTY access. Design your setup scripts with this as the primary use case, not the exception.
96+
97+
### 2. **Provide Clear Post-Install Instructions**
98+
When interactive setup isn't possible, give users an obvious next step:
99+
100+
```bash
101+
echo "⚠️ API key setup required!"
102+
echo "Run: claude setup api-key"
103+
echo "Or manually edit: ~/.config/letter-for-my-future-self/config.json"
104+
```
105+
106+
### 3. **Offer Multiple Configuration Paths**
107+
Consider supporting:
108+
- Interactive prompts (when possible)
109+
- Environment variables
110+
- Config files
111+
- Command-line flags
112+
- In-session setup commands
113+
114+
### 4. **Test in Real Environments**
115+
Local testing with `./script.sh` doesn't replicate how your script runs in production. Test through the actual installation mechanism your users will encounter.
116+
117+
## The Road Ahead
118+
119+
This debugging session revealed several improvements for the next iteration:
120+
121+
1. **Enhanced setup script** that detects non-interactive mode and provides helpful next steps
122+
2. **In-session configuration** via a `/letter-setup` command for users who need to configure keys later
123+
3. **Better error messaging** that guides users toward successful configuration
124+
4. **Documentation updates** with clear setup instructions for different environments
125+
126+
## Final Thoughts
127+
128+
Sometimes the most educational bugs aren't the complex algorithmic puzzles—they're the simple assumptions that don't hold up in the real world. This TTY detection issue was a good reminder that the gap between "works on my machine" and "works for users" often lies in the environmental details we take for granted.
129+
130+
The next time you're writing a setup script, ask yourself: "What happens when this runs in a Docker container? In a GitHub Action? Through a package manager hook?" Your future self (and your users) will thank you.
131+
132+
---
133+
134+
*Have you encountered similar installation gotchas? Share your debugging war stories—I'd love to hear how you've navigated the gap between development and deployment environments.*

0 commit comments

Comments
 (0)