Skip to content

feat: agent install path — paste-able prompt + install.json contract + llms.txt - #12

Open
todddickerson wants to merge 1 commit into
mainfrom
feat-agent-install
Open

feat: agent install path — paste-able prompt + install.json contract + llms.txt#12
todddickerson wants to merge 1 commit into
mainfrom
feat-agent-install

Conversation

@todddickerson

@todddickerson todddickerson commented Aug 19, 2026

Copy link
Copy Markdown
Owner

What & why

The "agent install" path Todd asked for on 2026-08-17 — "give an 'agent prompt' as well for claude/openclaw/hermes/etc easy install via agents" — which PR #11 (brew cask + curl installer) didn't ship. This adds the agent-facing surface: a copy-paste prompt, a machine-readable install contract, and an llms.txt discovery file, so a coding agent (Claude Code, OpenClaw, Cursor, Codex, Hermes) can install and verify FunButton for its user and then hand off the macOS permission grants a human must do by hand.

Changes

  • AGENT-INSTALL.md (repo root) — the headline artifact. A model-agnostic, copy-paste prompt: preferred order brew → curl → manual (each with exact commands + success/failure detection); a four-check VERIFY block (app present, no com.apple.quarantine, version == latest, launch log shows Whisper + llama-server up); an explicit STOP-and-hand-off for Microphone / Accessibility / Input Monitoring with the exact System Settings panes (no agent can grant TCC permissions — the doc says so instead of faking it); and the ~1.1 GB first-run model download surfaced up front. No emoji headings, no slop, never spctl --master-disable.
  • apps/web/app/install.json/route.ts — machine-readable contract at https://funbutton.ai/install.json (schema_version: "1"). Dynamic edge route: resolves the latest version + DMG SHA-256 live from the GitHub API digest field (same source as /download), so it never drifts per release; falls back to a last-known-good pin if the API is down. Includes platform/arch, install methods + commands, required TCC permissions (permissions_grantable_by_agent: false), model size + location, and a verify block.
  • apps/web/app/llms.txt/route.ts — discovery surface at https://funbutton.ai/llms.txt (llmstxt.org convention): terse plain-text what/how/permissions + pointers to /install.json and /install.sh.
  • apps/web/app/page.tsx — a compact, deliberately secondary "installing with a coding agent?" card under the numbered install methods (copy-to-clipboard prompt + links to /install.json and /llms.txt). Brew stays the loud primary path for humans. Text-label copy button (terminal aesthetic, no emoji, no new dep).
  • README.md — "Install with a coding agent" subsection cross-linking AGENT-INSTALL.md + the two endpoints.
  • PROGRESS.md — new entry.

End-to-end proof (followed AGENT-INSTALL.md verbatim, on the Mac Studio)

Uninstalled first, then ran my own doc's steps as if I were the agent. No faked screenshots — logs, xattr, and exit codes only.

Install (method 1, brew cask):

$ brew uninstall --cask funbutton
==> Uninstalling Cask funbutton
==> Removing App '/Applications/FunButton.app'

$ uname -sm
Darwin arm64

$ brew install --cask todddickerson/funbutton/funbutton
==> Installing Cask funbutton
==> Moving App 'FunButton.app' to '/Applications/FunButton.app'
🍺  funbutton was successfully installed!

Verify (all four pass):

a) test -d /Applications/FunButton.app && echo OK
   OK

b) xattr /Applications/FunButton.app
   com.apple.provenance          <- no com.apple.quarantine → PASS

c) defaults read /Applications/FunButton.app/Contents/Info CFBundleShortVersionString
   0.1.8
   install.json latest_version: 0.1.8   → MATCH

d) /Applications/FunButton.app/Contents/MacOS/funbutton  (launch, grep readiness)
   [INFO funbutton_lib::embedded_stt] embedded STT model loaded ("MTL0" backend, 376ms)
   [INFO funbutton_lib::embedded_llm] llama-server ready at http://127.0.0.1:58250 (1812ms)
   [INFO funbutton_lib] embedded llama-server ready at http://127.0.0.1:58250

(Models were already cached from a prior run, so no 1.1 GB re-download this pass — the doc warns about that download for a genuinely first run.)

Live gotcha caught + doc confirmed correct: brew auto-updated 6.0.17 → 6.0.18 mid-run, which adds a new tap-trust gate. I tested the true fresh-user path — removed funbutton from ~/.homebrew/trust.json, uninstalled, reinstalled:

$ brew install --cask todddickerson/funbutton/funbutton
==> Trusted cask todddickerson/funbutton/funbutton      <- naming the full user/tap/cask auto-trusts
==> Would install 1 cask: ...
   → exit 0, /Applications/FunButton.app present

So the doc's command works with no brew trust step. trust.json restored to its original state.

Endpoints serve (local prod next start — NOT deployed to prod)

/install.json → HTTP 200  application/json; charset=utf-8   (valid JSON, live latest_version 0.1.8 + correct sha256)
/llms.txt     → HTTP 200  text/plain; charset=utf-8
/install.sh   → HTTP 200  text/plain (no regression)
/             → HTTP 200  (landing shows the new "installing with a coding agent?" block)

Gates

  • cargo fmt --check: clean
  • cargo clippy --release --all-targets -- -D warnings: clean
  • cargo build --release: ok (Finished release in 6m 56s)
  • cargo test --release --lib: test result: ok. 78 passed; 0 failed; 7 ignored
  • macOS-26 crash-guard grep (rdev|TSMGetInputSource|TISCopy|UCKeyTranslate): doc comments only
  • apps/web next build (TypeScript) + eslint: clean
  • apps/worker tsc --noEmit: clean
  • Zero Rust/worker source touched. (vendor/ dylibs symlinked from the main checkout for the build, since vendor/ is gitignored.)

Not done (per instructions)

No release cut. Not deployed to production. No Telegram/Slack — Todd handles comms.

🤖 Generated with Claude Code

Summary by Sourcery

Enable coding agents to install and verify FunButton while clearly handing macOS security permissions back to the user.

New Features:

  • Add a copy-paste coding-agent installation prompt with automated verification guidance and explicit macOS permission handoff.
  • Expose a versioned machine-readable installation contract at /install.json with release metadata, installation methods, permissions, model requirements, and verification checks.
  • Add an llms.txt discovery endpoint for agent-friendly installation information.

Enhancements:

  • Add a secondary coding-agent installation card with clipboard support to the landing page.
  • Document coding-agent installation and agent-facing endpoints in the README.

Documentation:

  • Add comprehensive agent installation guidance covering supported platforms, installation fallbacks, first-run model downloads, verification, and required human permission grants.

Tests:

  • Record end-to-end installation and verification results for the documented Homebrew path and validate the new web endpoints locally.

Chores:

  • Record the agent-installation work and validation status in project progress tracking.

…+ llms.txt

Lets a coding agent (Claude Code, OpenClaw, Cursor, Codex, Hermes) install and
verify FunButton unattended, then hand off the three macOS TCC grants a human
must do by hand (no agent can grant them).

- AGENT-INSTALL.md: copy-paste, model-agnostic prompt. brew -> curl -> manual
  with success/failure detection; a 4-check VERIFY block (app present, no
  quarantine, version == latest, launch log shows Whisper + llama-server up);
  explicit STOP-and-hand-off for Microphone/Accessibility/Input Monitoring with
  exact panes; surfaces the ~1.1 GB first-run model download.
- apps/web/app/install.json: machine-readable contract (schema_version 1).
  Dynamic edge route resolving latest version + DMG sha256 live from the GitHub
  API digest, with a last-known-good fallback. Methods, TCC perms, model size,
  verify block.
- apps/web/app/llms.txt: discovery surface per the llms.txt convention.
- apps/web/app/page.tsx: secondary "installing with a coding agent?" card
  (copy button + links). Brew stays the primary human path.
- README.md: "Install with a coding agent" section cross-linking AGENT-INSTALL.md.

Proved end to end by following AGENT-INSTALL.md verbatim on the Mac Studio:
brew cask install, no quarantine, version 0.1.8, launch log shows
"embedded STT model loaded" + "llama-server ready". /install.json and /llms.txt
serve 200 with correct content-type. All gates green (cargo fmt/clippy/build/
test 78 passed, worker tsc, web build+eslint, crash-guard grep doc-only).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@sourcery-ai

sourcery-ai Bot commented Aug 19, 2026

Copy link
Copy Markdown

Reviewer's Guide

Adds an agent-focused installation path for FunButton, including a copy-paste prompt, machine-readable install contract, and LLM discovery surface, and surfaces these via the web landing page and README.

Sequence diagram for resolving install.json via GitHub API

sequenceDiagram
  participant Agent
  participant InstallJsonRoute as install.json_route
  participant GitHubAPI as GitHub_API

  Agent->>InstallJsonRoute: GET /install.json
  activate InstallJsonRoute
  InstallJsonRoute->>InstallJsonRoute: resolveRelease()
  activate InstallJsonRoute
  InstallJsonRoute->>GitHubAPI: fetch /repos/todddickerson/funbutton/releases/latest
  activate GitHubAPI
  GitHubAPI-->>InstallJsonRoute: Release JSON
  deactivate GitHubAPI
  InstallJsonRoute->>InstallJsonRoute: pickDmg(rel)
  InstallJsonRoute->>InstallJsonRoute: sha256From(dmg.digest)
  InstallJsonRoute-->>InstallJsonRoute: resolved release | null
  deactivate InstallJsonRoute

  alt resolved release
    InstallJsonRoute->>InstallJsonRoute: buildContract(resolved)
  else no release or error
    InstallJsonRoute->>InstallJsonRoute: buildContract(FALLBACK)
  end

  InstallJsonRoute-->>Agent: 200 JSON (schema_version 1, latest_version, download, install_methods, verify)
  deactivate InstallJsonRoute
Loading

Sequence diagram for the new agent install UI copy prompt

sequenceDiagram
  actor User
  participant Browser
  participant AgentInstall as AgentInstall_component
  participant CopyButton as CopyButton_component
  participant Clipboard as navigator.clipboard

  User->>Browser: Open landing page
  Browser->>AgentInstall: render AgentInstall()
  AgentInstall->>CopyButton: render CopyButton(text=AGENT_PROMPT, label="copy prompt")

  User->>CopyButton: click button
  activate CopyButton
  CopyButton->>Clipboard: writeText(text)
  alt writeText success
    Clipboard-->>CopyButton: Promise resolved
    CopyButton->>CopyButton: setCopied(true)
    CopyButton->>User: label rendered as "copied" (~1.5s)
    CopyButton->>CopyButton: setCopied(false)
  else writeText throws
    Clipboard-->>CopyButton: error
    CopyButton->>User: prompt remains selectable for manual copy
  end
  deactivate CopyButton
Loading

File-Level Changes

Change Details Files
Introduce an agent-focused install prompt and documentation for FunButton.
  • Create AGENT-INSTALL.md describing preflight checks, three install methods, a four-step verification sequence, and a mandatory human handoff for macOS permissions.
  • Document model download size and behavior, platform constraints, and why TCC permissions cannot be granted by agents.
  • Provide guidance for agents to use the machine-readable install.json instead of scraping HTML, and link all relevant endpoints.
AGENT-INSTALL.md
README.md
PROGRESS.md
Expose a dynamic machine-readable install contract endpoint for agents.
  • Implement an edge runtime route that fetches the latest GitHub release metadata and arm64 DMG asset, with a fallback pin when the API is unavailable.
  • Parse GitHub asset digest to extract SHA-256, select appropriate DMG, and enrich with static install metadata such as methods, permissions, models, and verification commands.
  • Serve structured JSON with caching headers, a versioned schema, and documentation links for agents.
apps/web/app/install.json/route.ts
Add an llms.txt discovery endpoint following llmstxt.org conventions.
  • Create a static text/plain route describing FunButton, platform and signing facts, model download behavior, and required macOS permissions.
  • List preferred install methods and commands, and point agents to the install.json contract, agent prompt, installer script, download URL, and source repo.
  • Configure caching headers and static rendering for the discovery file.
apps/web/app/llms.txt/route.ts
Integrate an agent-install UI card and copy-to-clipboard prompt on the landing page.
  • Add an AgentInstall component that renders a compact card under existing install methods with a copy-able agent prompt and links to install.json and llms.txt.
  • Define a model-agnostic AGENT_PROMPT string that references install.json and AGENT-INSTALL.md, emphasizes Homebrew as preferred, and clarifies macOS permission handoff.
  • Implement a minimal CopyButton component using the Clipboard API, with optimistic feedback state, accessible labeling, and fallback behavior when clipboard writes fail.
apps/web/app/page.tsx

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey - I've left some high level feedback:

  • In the install.json contract, the manual install method sets clears_quarantine: false even though its commands include xattr -dr com.apple.quarantine on the app; consider aligning this flag with the behavior or clarifying that the clearance is manual rather than automatic.
  • The new CopyButton component relies directly on navigator.clipboard without a feature check; adding a guard for environments where the Clipboard API is unavailable or restricted (and possibly a non-async fallback) would make the button behavior more predictable across browsers and contexts.
  • The install.json route mixes a fairly large static schema with dynamic release resolution logic in a single file; extracting the static contract shape and helper types/constants into a separate module could improve readability and make future schema evolution easier to manage.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- In the install.json contract, the `manual` install method sets `clears_quarantine: false` even though its commands include `xattr -dr com.apple.quarantine` on the app; consider aligning this flag with the behavior or clarifying that the clearance is manual rather than automatic.
- The new CopyButton component relies directly on `navigator.clipboard` without a feature check; adding a guard for environments where the Clipboard API is unavailable or restricted (and possibly a non-async fallback) would make the button behavior more predictable across browsers and contexts.
- The install.json route mixes a fairly large static schema with dynamic release resolution logic in a single file; extracting the static contract shape and helper types/constants into a separate module could improve readability and make future schema evolution easier to manage.

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant