improve status maintenance workflow prompt (#419)

- update STATUS.md with accurate teal.fm integration context (speculative, awaiting feedback)
- rewrite workflow prompt to enforce 250 line limit
- add explicit first episode vs subsequent episode detection
- add detailed tone requirements with examples of what NOT to say
- add forbidden phrases list to reduce sycophancy
- instruct agent to fetch ATProto docs for accurate technical explanations

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: Claude <noreply@anthropic.com>

authored by zzstoatzz.io Claude and committed by GitHub d3dbe2ee 5c1e0b47

Changed files
+117 -72
.github
+102 -52
.github/workflows/status-maintenance.yml
··· 48 48 claude_args: | 49 49 --allowedTools "Read,Write,Edit,Bash,Fetch" 50 50 prompt: | 51 - you are maintaining the plyr.fm (pronounce as "player FM") project status file. 51 + you are maintaining the plyr.fm (pronounced "player FM") project status file. 52 52 53 - ## context 53 + ## critical rules 54 54 55 - - project started: november 2025 56 - - today's date: run `date` to get current date 57 - - this may be the first time this workflow has run 58 - - .status_history/ directory may not exist yet 55 + 1. STATUS.md MUST be kept under 250 lines. this is non-negotiable. 56 + 2. archive content MUST be moved to .status_history/, not deleted 57 + 3. podcast tone MUST be dry, matter-of-fact, slightly sardonic - NOT enthusiastic or complimentary 59 58 60 59 ## task 1: gather temporal context 61 60 62 - before writing any transcript, understand the timeline: 63 - 1. run `git log --oneline --since="1 week ago"` to see recent commits 64 - 2. run `git log --oneline -30` to see the last 30 commits with dates 65 - 3. note the actual dates of changes - don't present old work as "just shipped" 61 + run these commands: 62 + ```bash 63 + date 64 + git log --oneline --since="1 week ago" 65 + git log --oneline -30 66 + ls -la .status_history/ 2>/dev/null || echo "no archive directory yet" 67 + wc -l STATUS.md 68 + ``` 69 + 70 + determine: 71 + - what is today's date? 72 + - what shipped in the last week vs earlier? 73 + - does .status_history/ exist? 74 + - how many lines is STATUS.md currently? 75 + - is this the FIRST episode (no .status_history/ exists)? 66 76 67 - ## task 2: archive old sections (if needed) 77 + ## task 2: archive old sections (MANDATORY if over 250 lines) 68 78 69 - read STATUS.md and count the lines. 79 + if STATUS.md > 250 lines: 80 + 1. create .status_history/ directory if it doesn't exist 81 + 2. identify section boundaries (look for "---" separators and "### " headers with dates) 82 + 3. move OLDEST sections to .status_history/YYYY-MM.md (grouped by month) 83 + 4. keep ONLY the most recent content totaling ~200-250 lines in STATUS.md 84 + 5. preserve the document structure (keep "## recent work" header, "## immediate priorities", etc) 85 + 6. do NOT summarize archived content - move it verbatim 70 86 71 - if over 250 lines: 72 - 1. identify natural section boundaries (marked by "---" or headers like "### " with dates) 73 - 2. keep the most recent ~250 lines in STATUS.md 74 - 3. move older sections to .status_history/YYYY-MM.md files, grouped by month 75 - 4. create .status_history/ directory if it doesn't exist 76 - 5. preserve raw content - don't summarize or modify the archived text 87 + example: if STATUS.md has sections from Nov 10, Nov 12, Nov 24, Nov 27, Dec 1: 88 + - move Nov 10-24 content to .status_history/2025-11.md 89 + - keep Nov 27 and Dec 1 content in STATUS.md 77 90 78 - if 250 lines or fewer, skip archiving. 91 + VERIFY: run `wc -l STATUS.md` after archiving. it MUST be under 250 lines. 79 92 80 93 ## task 3: generate audio overview 81 94 82 95 skip_audio input: ${{ inputs.skip_audio }} 83 96 84 97 if skip_audio is false: 85 - 1. write a 2-3 minute podcast script to podcast_script.txt 86 - - two hosts having a casual conversation 87 - - host personalities should be inspired by Gilfoyle and Dinesh from Silicon Valley 88 - - focus on recently shipped features from the git history (except for the first episode) 89 - - format: "Host: ..." and "Cohost: ..." lines 90 - - IMPORTANT: "plyr.fm" is pronounced "player FM" (not "plir" or spelling it out) 91 - - do not over-sensationalize / over-compliment the project's significance / achievements / progress 92 98 93 - temporal awareness: 94 - - use the git history to understand WHEN things actually shipped 95 - - if this is the first episode, acknowledge the project started in november 2025 96 - - reference time correctly: "last week they shipped X" vs "back in november they built Y" 97 - - don't present month-old work as if it just happened 99 + ### understand the project first 98 100 99 - tone guidelines: 100 - - accessible to non-technical listeners, but don't dumb it down 101 - - focus on user impact: what can people do now that they couldn't before? 102 - - use intuitive analogies to explain technical concepts in terms of everyday experience 103 - - matter-of-fact delivery, not hype-y or marketing-speak 104 - - brief, conversational - like two friends catching up on what shipped 105 - 106 - read upstream documentation: 107 - - docs/**.md contains a lot of useful information 108 - - you can Fetch atproto.com to understand primitives that are relevant to the project 101 + before writing the script, read: 102 + - STATUS.md (the current state) 103 + - docs/deployment/overview.md if it exists 104 + - Fetch https://atproto.com/guides/overview to understand ATProto primitives 105 + - Fetch https://atproto.com/guides/lexicon to understand NSIDs and lexicons 109 106 110 - 2. run: uv run scripts/generate_tts.py podcast_script.txt update.wav 107 + this context helps you explain things accurately without over-simplifying. 108 + 109 + ### determine episode type 110 + 111 + check if .status_history/ directory exists: 112 + - if NO .status_history/ exists: this is the INAUGURAL episode 113 + - if .status_history/ exists: this is a SUBSEQUENT episode 114 + 115 + ### write the podcast script 116 + 117 + write to podcast_script.txt with "Host: ..." and "Cohost: ..." lines. 118 + 119 + INAUGURAL EPISODE (first time): 120 + - introduce what plyr.fm is: decentralized music streaming on ATProto 121 + - explain the core value prop: your music data lives in your PDS, portable between apps 122 + - cover the technical foundation that's been built (summarize from STATUS.md) 123 + - set expectations: this is an early-stage project, rough edges exist 124 + - tone: "here's what we're building and why it matters" 125 + 126 + SUBSEQUENT EPISODES: 127 + - focus on what actually shipped since last episode 128 + - use git history to determine timing ("last week" vs "earlier this month") 129 + - don't re-explain the whole project - listeners already know 130 + - tone: "here's what changed" 131 + 132 + ### tone requirements (CRITICAL) 133 + 134 + the hosts should sound like two engineers who: 135 + - are mildly amused by the absurdity of building things 136 + - acknowledge problems and limitations honestly 137 + - don't use superlatives ("amazing", "incredible", "exciting") 138 + - don't congratulate the project or its creator 139 + - explain technical concepts through analogy, not hype 140 + - are slightly sardonic but not mean 141 + 142 + BAD example: 143 + "Host: Wow, they've done an incredible job building this decentralized music platform!" 144 + "Cohost: Absolutely! The ATProto integration is amazing!" 111 145 112 - 3. delete the podcast script (we only need the audio): rm podcast_script.txt 146 + GOOD example: 147 + "Host: So someone built a music streaming thing on ATProto." 148 + "Cohost: Right, the protocol Bluesky uses. The idea being your playlists and play history live in your personal data server instead of Spotify's database." 149 + "Host: Which means if plyr.fm disappears tomorrow, you still have your data." 150 + "Cohost: In theory. Whether anyone else builds a client that reads it is another question." 113 151 114 - 4. DO NOT upload to plyr.fm yet - that happens after PR merge 152 + forbidden phrases: 153 + - "exciting", "amazing", "incredible", "impressive", "great job" 154 + - "the team has done", "they've really", "fantastic work" 155 + - any variation of congratulating or praising the project 115 156 116 - ## task 4: open PR with changes 157 + pronunciation: "plyr.fm" = "player FM" (not "plir" or spelled out) 117 158 118 - if any files changed (.status_history/*, STATUS.md) OR audio was generated: 119 - 1. create a new branch: git checkout -b status-maintenance-<date> 120 - 2. git add .status_history/ STATUS.md update.wav (do NOT add podcast_script.txt) 121 - 3. commit with message "chore: weekly status maintenance" 122 - 4. push the branch: git push -u origin status-maintenance-<date> 123 - 5. create a PR using: gh pr create --title "chore: weekly status maintenance" --body "automated status archival and audio overview" 159 + target length: 2-3 minutes spoken (~300-400 words) 160 + 161 + ### generate audio 162 + 163 + run: uv run scripts/generate_tts.py podcast_script.txt update.wav 164 + then: rm podcast_script.txt 165 + 166 + ## task 4: open PR 167 + 168 + if any files changed: 169 + 1. git checkout -b status-maintenance-$(date +%Y%m%d) 170 + 2. git add .status_history/ STATUS.md update.wav 171 + 3. git commit -m "chore: weekly status maintenance" 172 + 4. git push -u origin status-maintenance-$(date +%Y%m%d) 173 + 5. gh pr create --title "chore: weekly status maintenance" --body "automated status archival and audio overview" 124 174 125 - if nothing changed, just report that no maintenance was needed. 175 + if nothing changed, report that no maintenance was needed. 126 176 127 177 env: 128 178 GOOGLE_API_KEY: ${{ secrets.GOOGLE_API_KEY }}
+15 -20
STATUS.md
··· 41 41 42 42 ## recent work 43 43 44 - ### now-playing API for teal.fm/Piper integration (PR #416, Dec 1, 2025) 44 + ### now-playing API (PR #416, Dec 1, 2025) 45 45 46 - **motivation**: enable Piper (teal.fm) to display what users are currently listening to on plyr.fm 46 + **motivation**: expose what users are currently listening to via public API 47 47 48 48 **what shipped**: 49 - - **now-playing endpoint** (`GET /now-playing/{did}`): 50 - - returns currently playing track for a given user DID 51 - - includes track metadata (title, artist, album, cover art) 52 - - includes playback position and timestamp 53 - - public endpoint (no auth required) 54 - - returns 404 when user isn't playing anything 55 - - **playback tracking**: 56 - - stores last playback state in `now_playing` table 57 - - updated when users interact with player 58 - - includes track_id, position, timestamp, user DID 59 - - **privacy considerations**: 60 - - opt-in via user preferences (future enhancement) 61 - - currently public for all users who play tracks 62 - - DIDs are already public identifiers 49 + - `GET /now-playing/{did}` and `GET /now-playing/by-handle/{handle}` endpoints 50 + - returns track metadata, playback position, timestamp 51 + - 204 when nothing playing, 200 with track data otherwise 52 + - public endpoints (no auth required) - DIDs are already public identifiers 63 53 64 - **impact**: 65 - - enables cross-platform integrations (Piper can show "listening to X on plyr.fm") 66 - - lays groundwork for richer presence features 67 - - demonstrates plyr.fm as an API-first platform 54 + **speculative integration with teal.fm**: 55 + - opened draft PR to Piper (teal.fm's scrobbling service): https://github.com/teal-fm/piper/pull/27 56 + - adds plyr.fm as a source alongside Spotify and Last.fm 57 + - tested end-to-end: plyr.fm → Piper → ATProto PDS (actor.status records) 58 + - **status**: awaiting feedback from teal.fm team 59 + - **alternative approach suggested**: teal.fm team suggested plyr.fm could write directly to `fm.teal.*` lexicons 60 + - concern: this couples plyr.fm to teal's internal schema - if they change lexicons, we'd need to fast-follow 61 + - Piper approach keeps cleaner boundaries: plyr.fm exposes API, Piper handles teal.fm integration 62 + - decision pending further discussion with teal.fm maintainers 68 63 69 64 --- 70 65