feat(fred): /fred:auth stores the API key, and document updating - #44
Merged
Conversation
Two things. /fred:auth opens the operating system's own password prompt, verifies the key against FRED, and writes it to ~/.fred-mcp/credentials.json at 0600. Re-running always overwrites, which is the rotation path. The command deliberately does not collect the key itself. A key pasted into a conversation is in the transcript and in the context window, and neither is something a user can rotate away, so commands/auth.md instructs the agent not to ask for it and delegates to scripts/save-credentials.sh, which reads the prompt directly. osascript on macOS, zenity or kdialog on Linux, a masked terminal read otherwise. Nothing the script writes to stdout contains the key, and a test runs the rejection path to prove it. Verification happens before the write, so a mistyped key during a rotation cannot overwrite a working one. The shape check is the same rule as client.py, asserted in both places so they cannot drift. The root README gains an Updating section: refreshing the marketplace is what makes a newly merged plugin visible at all, and install and update are not interchangeable. Folded two sentences that were already duplicated in that section.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Two asks from #30 follow-up: a credential command for fred, and the update commands in the repo README.
/fred:authOpens your OS's own password prompt, verifies the key against FRED, writes it to
~/.fred-mcp/credentials.jsonat0600. Re-running always overwrites, which is the rotation path.The command does not collect the key itself, and that is the design. A key pasted into a conversation is in the transcript and in the context window, and neither is something you can rotate away. So
commands/auth.mdexplicitly instructs the agent not to ask for it and to delegate toscripts/save-credentials.sh, which reads the prompt directly:osascriptdialog,with hidden answerso the field is maskedzenity --password, elsekdialog --passwordread -sfrom/dev/ttyVerification happens before the write, so a mistyped key during a rotation cannot overwrite a working one. The shape check (32 lowercase alphanumeric) is the same rule as
client.py, asserted in both places so they cannot drift.curl's stderr is discarded during verification, because its error text can echo the URL and the key is a query parameter in it.Verified, not assumed
Round-tripped:
resolve_api_key()reads what the script writes. The key does not appear in the script's stdout or stderr on any path, and a test asserts that by running the rejection path with a sentinel value.The AppleScript is multi-line, which is a real hazard, so I checked it two ways:
osacompilefor syntax, then an actual render withgiving up after 1to confirm it displays from a non-interactive context. Both pass.make checknow runs the script's own--selftest, following the same pattern as tastytrade'sscripts/calendars.py: shipped payload that lives outsidesrc/and that pytest therefore never imports.299 tests, 98% coverage.
README
Merging to
mainpublishes; what each machine needs is a cache refresh. Untilclaude plugin marketplace update walkerhughesruns, a newly added plugin is invisible locally however many times you try to install it, which is exactly what your fred install hit.Also documents that
installandupdateare not interchangeable, sinceinstallno-ops on an existing plugin and reads as "nothing happened". Folded two sentences that section already duplicated.Note
FRED_API_KEY_STDIN=1is an escape hatch for scripted setup, used by the tests. The slash command never sets it.