diff --git a/LAUNCH.md b/LAUNCH.md new file mode 100644 index 0000000..ef1c98b --- /dev/null +++ b/LAUNCH.md @@ -0,0 +1,171 @@ +# Launch playbook — `opencode-ruby` v0.0.1-alpha1 + +Reference materials for shipping. Not part of the gem; lives at the repo root for the human launching it. + +## 1. Publish to Rubygems + +`~/.gem/credentials` is not set up on the dev machine. To push: + +```sh +gem signin # one-time, follow prompts to log in +gem push opencode-ruby-0.0.1.alpha1.gem # builds in pkg/ via rake build, or use the local .gem file +sleep 30 # rubygems indexing +curl -s "https://rubygems.org/api/v1/gems/opencode-ruby.json" | jq '.name, .version' +``` + +Expected: `"opencode-ruby"`, `"0.0.1.alpha1"`. + +After successful push, update `ajaynomics/ajent-rails` Gemfile (PR #844 land swap): + +```ruby +gem "opencode-ruby", "~> 0.0.1.alpha1" +# (drop the git+tag pin) +``` + +## 2. Take three screenshots + +Three is the bar Tobi set. Crisp, real, on a real terminal. + +### Screenshot 1 — terminal running the quickstart + +```sh +# Start a local opencode server (in another terminal): +opencode serve --port 4096 + +# Then in a clean terminal: +ruby -ropencode-ruby -e ' +client = Opencode::Client.new(base_url: "http://localhost:4096") +session = client.create_session(title: "Demo") +reply = client.stream(session[:id], "Explain monads in two sentences.") do |part| + print part["content"] if part["type"] == "text" +end +puts +puts +puts "(#{reply.tool_parts.size} tool calls, #{reply.parts_json.size} parts total)" +' +``` + +Capture a screenshot showing the streaming text + final tool/part count line. + +Recommended terminal: Ghostty with a clean theme, large font (16-18pt). Resize to ~120x30. + +Save as `assets/screenshots/01-quickstart.png`. + +### Screenshot 2 — rubygems.org page + +After `gem push` + indexing, screenshot the rubygems.org page for the gem. Crop to the title + summary + install command. ~1200×500 px. + +Save as `assets/screenshots/02-rubygems.png`. + +### Screenshot 3 — gem listed in `Gemfile.lock` of a host app + +After PR #844 lands, take a screenshot of the relevant 5-line `Gemfile.lock` excerpt showing the gem at v0.0.1.alpha1. + +Save as `assets/screenshots/03-gemfile-lock.png`. + +### Embed in README + +Add to top of README, right after the title: + +```markdown +![Quickstart](assets/screenshots/01-quickstart.png) +``` + +## 3. Announcement drafts + +Three channels, all under 280 chars unless noted. Don't post until at least one of the screenshots is in the README. + +### r/ruby (Reddit) + +Title: **opencode-ruby v0.0.1-alpha — idiomatic Ruby client for OpenCode** + +Body: + +> Shipping an early alpha of `opencode-ruby` — a hand-rolled Ruby SDK for the OpenCode agent platform (https://opencode.ai). +> +> Single headline API: +> +> ```ruby +> reply = client.stream(session_id, "Explain monads") do |part| +> print part["content"] if part["type"] == "text" +> end +> reply.full_text +> ``` +> +> Block-form streaming, typed value-object responses, automatic SSE reconnection, zero Rails coupling at the client level. Complementary to Eric Guo's [`opencode_client`](https://rubygems.org/gems/opencode_client) which auto-generates from OpenAPI — pick whichever fits your taste. +> +> Repo: https://gitea.krishnan.ca/ajaynomics/opencode-ruby +> Rubygems: https://rubygems.org/gems/opencode-ruby +> +> Looking for feedback, especially from Rails developers building chat experiences on OpenCode. A separate `opencode-rails` (with `acts_as_opencode_session`) is in the design doc but deferred until external demand surfaces — see the issue tracker if that's you. + +### dev.to + +Title: **Shipping a Ruby SDK for OpenCode — block-form streaming, value-object returns, zero ceremony** + +(Longer post — ~600-800 words. Skeleton:) + +1. **The problem.** OpenCode is the self-hostable agent platform. Ruby developers landing on it from Hacker News need a way to integrate from Ruby. Eric Guo's auto-generated `opencode_client` covers every endpoint exhaustively; this gem covers the small idiomatic surface. +2. **The postcard.** Three lines of setup, four lines of work, full streaming. (Use the screenshot.) +3. **Design choices that mattered.** + - Block-form streaming is the headline; `stream_events` is the lower seam. + - Reply::Result is a Struct, not a Hash — typed shape, both `.full_text` and `[:full_text]` access. + - Instrumentation is a pluggable adapter, not Rails-bound (works with AS::Notifications, OpenTelemetry, stdout). + - Error model is exceptions, not return values (`throwOnError: true` equivalent of the TS SDK). +4. **What's not in the gem.** `acts_as_opencode_session`, generators, ActiveRecord persistence. The `examples/conversation_recipe.rb` blueprint demonstrates the Rails pattern in ~140 lines of plain ActiveRecord. +5. **Demand signal.** If you want `opencode-rails`, file an issue. We're calibrating against real Rails-shop demand, not stars/installs. +6. **Where to find it.** Rubygems, Gitea repo, opencode.ai docs (TBD link). + +### Twitter / Bluesky / Mastodon (short) + +> opencode-ruby v0.0.1-alpha is live: an idiomatic Ruby client for @opencode_ai. +> +> ``` +> reply = client.stream(session_id, "...") { |part| print part["content"] } +> reply.full_text +> ``` +> +> Block streaming, Reply::Result Struct, no Rails coupling. https://rubygems.org/gems/opencode-ruby + +## 4. Friendly note to Eric Guo + +`opencode_client` (Eric's gem) is the auto-generated counterpart. Cross-linking + a head's-up is just good manners. + +Send via GitHub message or email (his gem page lists his contact). Draft: + +> Subject: Heads-up: opencode-ruby (complementary alternative) +> +> Hi Eric, +> +> I just shipped `opencode-ruby` — a hand-rolled idiomatic Ruby client for OpenCode, intentionally complementary to your `opencode_client`. My gem covers a small block-form-streaming surface aimed at Rails developers; yours covers every endpoint with generated types. +> +> README links your gem near the bottom: +> +> > "Want every OpenCode endpoint auto-generated from the OpenAPI spec? Use `opencode_client`. This gem is the hand-rolled idiomatic alternative." +> +> Happy to coordinate if you'd like — link from your README, joint blog post, whatever fits. Either way, just wanted to give you a friendly heads-up that there's a sibling gem with non-overlapping shape. +> +> Best, +> Ajay +> https://gitea.krishnan.ca/ajaynomics/opencode-ruby + +## 5. Demand-signal tracking (60-day window) + +Per design D18, the question whether to invest in `opencode-rails` rides on visible Rails-shop demand. Track: + +| Signal | Where | Threshold | +|---|---|---| +| GitHub/Gitea stars | repo page | ≥ 10 | +| Rubygems install count | https://rubygems.org/gems/opencode-ruby | ≥ 50 | +| Substantive issues | repo issue tracker | ≥ 3 (asking for features, not bugs) | +| Issues asking specifically for `acts_as_opencode_session` | repo | ≥ 1 | +| External Rails apps using `examples/conversation_recipe.rb` | grep, social mentions | ≥ 1 | + +At day 60, decide: +- All thresholds hit AND ≥ 1 acts_as_* request → start opencode-rails design doc. +- Some thresholds hit but no acts_as_* signal → stay the course; keep the recipe file as canonical. +- No thresholds hit → repo is dormant; revisit when something changes upstream. + +## 6. Friendly note to OpenCode maintainers + +If adoption picks up, propose donating the repo to anomalyco (OpenCode's org) per design D2. Draft TBD — only do it after the 60-day window confirms a healthy user base.