Agent skill

Gumroad Prod Console

by antiwork in antiwork/gumroad

Execute read-only Ruby/Rails commands against Gumroad's production database for debugging and investigation.

MITAuto-check: notesDevelopment

Install Gumroad Prod Console

skills CLI
$ npx skills add antiwork/gumroad --skill gumroad-prod-console -a claude-code

Project install by default; add -g for ~/.claude/skills/.

GitHub CLI
$ gh skill install antiwork/gumroad gumroad-prod-console --agent claude-code

Project scope by default; add --scope user for a personal install. Needs GitHub CLI 2.90.0 or later (public preview).

Manual copy
$ git clone --depth 1 https://github.com/antiwork/gumroad.git skills-src && mkdir -p .claude/skills && cp -r skills-src/.agents/skills/gumroad-prod-console .claude/skills/gumroad-prod-console && rm -rf skills-src

Use ~/.claude/skills/ instead of .claude/skills for a personal install. The folder must contain SKILL.md.

Claude Code skills documentation · loads skills from .claude/skills/

Facts

Skill name
gumroad-prod-console
GitHub stars
9.8k
Token cost
~2.9k tokens
SKILL.md length
1,376 words
Files
6 (incl. scripts, references)
Skills in repo
6
Repo updated
First seen
Licence
MIT

At a glance

Execute read-only Ruby/Rails commands against Gumroad's production database for debugging and investigation.

  • The user needs to debug production issues
  • SKILL.md covers Execution, Safety, Gumroad-specific gotchas and Requirements, plus 1 more section
  • Runs Shell and Ruby scripts from its folder; calls bash and rails
  • Investigate user reports

What it does

Gumroad Prod Console is an agent skill from antiwork/gumroad. Execute read-only Ruby/Rails commands against Gumroad's production database for debugging and investigation. Use when the user needs to debug production issues, look up data, investigate user reports, check records, or query production state. Triggers on: "check in prod", "debug this in prod", "look up user/purchase/product in production", "production console", "investigate in prod", "query production", "what's happening in prod", "look up a user by email", "who bought this product", "why is this user blocked"…

Its SKILL.md is about 2.9k tokens, which your agent loads only when the skill is triggered. The skill folder holds 7 other files, including scripts and reference files (for example `references/common-queries.md`, `scripts/prod_query.sh` and `scripts/setup.sh`).

It sits in Development, covering Backend development and Debugging. It works with Ruby and Redis. The licence is MIT.

When your agent uses it

  • The user needs to debug production issues
  • Investigate user reports
  • Query production state
  • : check in prod

Example prompts

  • “check in prod”
  • “debug this in prod”
  • “look up user/purchase/product in production”
  • “/gumroad-prod-console”

Requirements

  • A Bash shell
  • Docker

What it can do on your machine

Read from SKILL.md and the folder at commit fe890ec. It shows what the files ask for, not the result of running them.

  • Tool permissions

    Pre-approves nothing: there is no allowed-tools line, so your agent's usual permission prompts apply.

    From allowed-tools in the SKILL.md frontmatter.

  • Runs code

    Ships 4 files in scripts/ (Shell and Ruby), which the agent can run.

    Shell commands in SKILL.md call:

    • bash
    • rails

    From the folder's file list and the shell code blocks in SKILL.md.

  • Network

    No URLs in SKILL.md.

    From URLs in SKILL.md, links to its own repository left out.

  • Credentials

    Names no API keys, tokens, secrets or passwords.

    From names ending in _API_KEY, _TOKEN, _SECRET, _KEY or _PASSWORD in SKILL.md.

Context cost

Gumroad Prod Console loads about 2.9k tokens when it runs, and up to ~3.3k if it reads all its reference files. Until then it costs about 172 tokens; SKILL.md has 1,376 words of instructions outside code blocks.

Always · name and description, kept in context so the agent knows when to use it
~172
When it runs · the whole SKILL.md, loaded when a task matches
~2.9k
With references · SKILL.md plus every file in references/, read only if the agent opens them
~3.3k

Estimates: characters ÷ 4, the usual rule of thumb; real counts depend on the model's tokenizer. Scripts and assets cost tokens only if the agent reads them.

Safety

Auto-check: notes

The automated check noted patterns worth knowing about, such as sudo or a known installer.

  • NoteMentions a .env fileSKILL.md:139
    script via `GUMROAD_DEPLOYMENT_DIR` and `.env.aws`, run the helper from the repo root to migrate those creds into an AWS
  • NoteMentions a .env fileSKILL.md:144
    -prod-console/scripts/setup.sh ~/path/to/.env.aws

Automated static check — not a guarantee. Review scripts before installing. It scans the text of SKILL.md for risky patterns (piping downloads into a shell, reading credential files, hidden Unicode, destructive commands); the scripts in this folder are not scanned.

SKILL.md

The full file from antiwork/gumroad at commit fe890ec, republished under its MIT licence (© antiwork). 1,376 words, ~2,948 tokens.

Download SKILL.mdSave it as .claude/skills/gumroad-prod-console/SKILL.md (or your agent's skills folder). This skill also uses 5 other files; get the full folder from GitHub.
name
gumroad-prod-console
description
Execute read-only Ruby/Rails commands against Gumroad's production database for debugging and investigation. Use when the user needs to debug production issues, look up data, investigate user reports, check records, or query production state. Triggers on: "check in prod", "debug this in prod", "look up user/purchase/product in production", "production console", "investigate in prod", "query production", "what's happening in prod", "look up a user by email", "who bought this product", "why is this user blocked", "find this sale/purchase", "how many X does Y have", or any request to examine live Gumroad data — even when the user doesn't say "prod" explicitly.

Gumroad production console

Read-only Rails runner against the production read replica via bastion SSH.

Execution

bash
.claude/skills/gumroad-prod-console/scripts/prod_query.sh 'puts User.count'
.claude/skills/gumroad-prod-console/scripts/prod_query.sh /tmp/query.rb
echo 'puts User.count' | .claude/skills/gumroad-prod-console/scripts/prod_query.sh

Multi-line queries: write a temp .rb file, pass its path. Bash tool timeout is ~120s — wrap slow queries in WithMaxExecutionTime.timeout_queries(seconds: 30) { ... }. Queries run against the read replica (DATABASE_WORKER_REPLICA1_HOST by default).

Follow-up queries are cheap — start scoped (one record, one field), then drill in as the investigation clarifies. Avoid the urge to return everything in a single large query.

Warm hops: prod_query.sh multiplexes SSH to the bastion (ControlPersist) and reuses the last-good instance IP for 10 minutes (PROD_IP_CACHE_TTL). A second query should skip EC2 discovery. Pin with PROD_INSTANCE_IP to skip it entirely. Tracked in gumroad-private#2197.

Persistent runner: the first replica-default query on a host boots a long-lived rails runner loop (scripts/prod_runner_loop.rb) inside the puma container; later queries are spooled to it and skip Rails boot entirely (~1s warm vs ~14s one-shot). The loop forks per query, keeps stdout/stderr separate, idles out after 30 minutes without work, and is replaced automatically when the local prod_runner_loop.rb changes. Non-default PROD_DB_HOST_VAR sessions (primary writes) always take the one-shot path; PROD_NO_RUNNER_LOOP=1 opts out.

Safety

  • Read-only. Never write, update, or delete.
  • No Redis KEYS or FLUSH*. prod_query.sh prepends scripts/redis_command_guard.rb, which refuses them: one KEYS over the ~4.6M-key primary blocks it for seconds and 500s the site. Use $redis.scan_each(match:, count: 1000).first(n).
  • Always .limit() / .first() / .take() — never unbounded result sets.
  • Prefer .pluck(:col, :col) over loading full AR objects.
  • Mask PII in output (truncate emails, addresses, payment details).
  • .explain before querying large tables without indexed conditions.
  • Emit structured output (JSON for complex, .inspect for simple) so results are parseable.

Gumroad-specific gotchas

External IDs, not primary keys

Admin URLs and public IDs use external IDs (ExternalId module — Base64 strings like aBcDeFgHiJkLmNoPqRsTuQ==), not integer PKs.

ruby
Purchase.find_by_external_id("aBcDeFgHiJkLmNoPqRsTuQ==")  # correct
Purchase.find("aBcDeFgHiJkLmNoPqRsTuQ==")                  # WRONG — treats it as a PK, silently returns the wrong record
Model naming
ModelNote
LinkThe product model (legacy name). find_by(unique_permalink:) for permalinks; alive scope for non-deleted.
InstallmentSubscriptions/recurring (not ActiveRecord's sense of "installment"). where(link_id:, alive: true).
CommentAdmin notes on records. content field, not body.
MerchantAccountProcessor-specific — users can have multiple. where(user_id:, charge_processor_id:).
Purchasesuccessful scope for completed sales. where(email:), where(link_id:).

User, Balance, Dispute, Follower, CustomDomain behave as names suggest.

Sidekiq queues

critical (12k limit — payouts, webhooks, receipts) → default (300k — general) → long (PDF stamping etc.) → low (expiry). Queue limits at app/controllers/healthcheck_controller.rb:28; worker ordering at docker/web/sidekiq_worker.sh.

DevTools (Gumroad-specific helpers)

See lib/utilities/dev_tools.rb:

  • DevTools.reindex_all_for_user(user_id) — reindex ES data
  • DevTools.reimport_follower_events_for_user!(user) — reimport follower analytics

For Gumroad-specific scopes and associations (alive, successful, unpaid_balance_cents, payments, products, Flipper checks, Sidekiq introspection), see references/common-queries.md.

Stale bastion host keys look like unhealthy instances

EC2 recycles private IPs, so the bastion's known_hosts accumulates stale keys and refuses the onward hop with REMOTE HOST IDENTIFICATION HAS CHANGED / Offending ECDSA key. From outside this is easy to mistake for a hung instance, and it silently shrinks the usable pool each time instances are replaced.

prod_query.sh catches them without touching the pin: a candidate is recorded as stale-keyed when a changed-key complaint names its address — including on a probe that looked healthy, since the forced command exits 0 after its own hop refused — and the run reports those addresses with the one-hop ssh-keygen -R command to run by hand.

  • The pin is never removed automatically. Every textbook trigger for a removal is something a pin exists to defend against: EC2 membership says the address is a pool member, not that the key it serves is the instance's, and a changed-key complaint is an alarm rather than proof of a recycle — deleting the entry and reconnecting pins whatever answered. Clearing is an explicit operator action, printed as a one-hop command.

  • Only genuinely outdated keys are reported. A plain timeout, a container that is still starting, or a network blip leaves the recorded key alone — only SSH naming that address counts. The onward hop usually just warns about a changed key and connects anyway (recycled IPs make that the steady state), so a warn-and-proceed failure stays on the patient-retry list too. Only an outright Host key verification failed refusal drops a candidate from the retry.

  • A pool rejected entirely for stale keys says so, with that same command, instead of the generic health-probe error.

  • LC_PAPER=127.0.0.1 means the bastion itself. The forced command jumps to whatever LC_PAPER names, and omitting the variable — or the -o SendEnv=LC_PAPER that ships it — fails with ssh: Could not resolve hostname; instance IPs run the command on that instance. Anything aimed at the bastion's own files goes through 127.0.0.1.

  • The warning text is often noise. A run can print the whole man-in-the-middle banner for a previous hop and still succeed. Judge by exit code and MARK output, not the banner. rc 255 is the transport dropping mid-flight, so the outcome is unknown — do not read it as a failed query. Any other nonzero rc whose only output is the banner means the query failed: look for Query process killed by SIGKILL or the query's own output.

Show full SKILL.md (574 more words)Show less
"No instance passed the health probe" usually means slow, not down

The candidate probe is deliberately impatient (20s) so one hung host cannot eat the caller's budget, but that also rejects hosts which are merely slow under load. When every candidate fails, a fleet-wide outage is the less likely reading.

prod_query.sh now retries the non-stale-key rejections with a patient probe before giving up, and says so (answered on the patient retry (slow, not unhealthy)). Only the all-rejected path pays for this.

Both passes draw down one shared 90s selection budget (PROD_SELECT_BUDGET), so picking a host can never consume the caller's whole ~120s Bash-tool window before the query starts — a large pool shortens each probe rather than adding to the total. A third of the budget is held back for the patient pass, so a pool of slow hosts cannot drain everything in the fast pass and starve the retry. Running out gives a distinct message that says the pool may just be slow, instead of the misleading "no instance passed the health probe". Raise the budget when you have more wall clock than the Bash tool allows:

bash
PROD_SELECT_BUDGET=240 timeout 560 bash .agents/skills/gumroad-prod-console/scripts/prod_query.sh q.rb

If you still get the hard error, force a host rather than assuming production is down:

bash
PROD_INSTANCE_IP=10.1.34.180 bash .agents/skills/gumroad-prod-console/scripts/prod_query.sh q.rb

This matters for watchers, not just interactive use: a cron that treats an unreadable console as "nothing to report" goes silent indefinitely and looks healthy. On 2026-07-29 all 8 candidates were rejected while a forced host answered the same query in 13s.

Grepping only for ^MARK can hide a total failure

... | grep "^MARK" on a run that never reached Rails returns empty with exit 0, which reads as "query worked, no rows". Capture to files and echo the exit code:

bash
timeout 560 prod_query.sh /tmp/q.rb > /tmp/q.out 2>/tmp/q.err; echo "exit=$?"
grep -a "^MARK" /tmp/q.out

Exit 124 = outer timeout (query too heavy). 255 = SSH itself failed: either the hop dropped before Rails started, or the transport dropped mid-flight with the spool state unknown — treat the query's outcome as unknown rather than failed.

association.unscoped reads the whole table

Link has no default_scope, so user.links already includes deleted rows — there is nothing to reach for .unscoped for. On an association it drops the user_id condition instead, leaving SELECT * FROM links (millions of rows). Iterating that gets the query process OOM-killed: the run exits nonzero, prints Query process killed by SIGKILL, and the stale host-key banner above it is not the cause. Use user.links (or Link.where(user_id: user.id)).

Keep Stripe API calls out of loops

The DB is fast; Stripe::Transfer.list / Charge.retrieve per record is what blows the timeout — even ~5 accounts with one Stripe call each can hit exit 124. Use raw SQL via ActiveRecord::Base.connection.select_all for population questions, and fetch at most 1–2 Stripe objects per run when you need live processor state.

Requirements

  • An AWS profile with ec2:DescribeInstances on the prod account. The script defaults to the profile gumroad-prod (created by scripts/setup.sh). Override by exporting AWS_PROFILE or setting PROD_AWS_PROFILE in your config file.
  • SSH access to your production bastion (defaults to bastion-production.gumroad.net)
Gumroad team one-time setup

If you previously ran this script via GUMROAD_DEPLOYMENT_DIR and .env.aws, run the helper from the repo root to migrate those creds into an AWS CLI profile:

bash
.claude/skills/gumroad-prod-console/scripts/setup.sh
# or pass an explicit path:
.claude/skills/gumroad-prod-console/scripts/setup.sh ~/path/to/.env.aws

The helper will also offer to append export AWS_PROFILE=gumroad-prod to your shell profile — say yes and reload the shell. After this, gumroad-private is no longer required to run the skill.

Configuration (self-hosters)

Defaults target Gumroad's prod infra. If you're running your own Gumroad fork, override by creating ~/.config/gumroad-prod-console.env:

bash
PROD_BASTION=bastion.mycompany.com
PROD_SECURITY_GROUP=my-web-sg
PROD_CONTAINER_FILTER=app-*
PROD_DB_HOST_VAR=MY_READ_REPLICA_HOST
PROD_AWS_PROFILE=my-aws-profile

Or export the same variables before invoking the script.

© antiwork, MIT. Rendered from Markdown: HTML in the file is shown as text, images as links, and headings moved down two levels. Raw file

Files

SKILL.md and 5 other files (scripts, references) in .agents/skills/gumroad-prod-console of antiwork/gumroad.

  • SKILL.md
  • references/common-queries.md
  • scripts/prod_query.sh
  • scripts/prod_runner_loop.rb
  • scripts/redis_command_guard.rb
  • scripts/setup.sh

Open the folder on GitHubat commit fe890ec

Compare with similar skills

Gumroad Prod Console next to the 5 skills that share the most tags, products or categories with it. Stars are the repository's; “used in” counts other GitHub owners with a copy.

Gumroad Prod Console compared with similar skills
SkillStarsUsed inTokensAuto-checkLicenceRepo updated
Gumroad Prod Console this skillantiwork/gumroad9.8k—~2.9kAutomated safety check: NotesMIT
Production Log Inspectionbikeindex/bike_index308—~3.6kAutomated safety check: PassAGPL-3.0
Railsericrisco/rsc-harness180—~3.1kAutomated safety check: PassMIT
Dhhmarckohlbrugge/37signals-skills724—~2.2kAutomated safety check: PassNone
Ruby Prodavila7/claude-code-templates33k8 repos~445Automated safety check: PassMIT
Dhh Rails Styledavekilleen/Dex4941 repos~1.7kAutomated safety check: PassMIT

Similar skills

  • Production Log Inspection

    bikeindex/bike_index

    Inspect the Bike Index production Rails logs downloaded by binxlogs and streamed with binxcat web / binxcat worker — JSON-per-request (Lograge) on web plus free-form background-job lines on worker…

    308 GitHub stars~3.6k tokensUpdated today
    Backend & APIsAuto-check passed
  • Rails

    ericrisco/rsc-harness

    A skill your agent uses when building or maintaining a Ruby on Rails app — models, controllers, views, routes and migrations; ActiveRecord associations, scopes and query performance; Hotwire (Turbo…

    180 GitHub stars~3.1k tokensUpdated today
    Backend & APIsAuto-check passed
  • Dhh

    marckohlbrugge/37signals-skills

    Review Ruby/Rails code like DHH would - direct, opinionated, allergic to over-engineering.

    724 GitHub stars~2.2k tokensUpdated 4 mo ago
    DevelopmentAuto-check passed
  • Ruby Pro

    davila7/claude-code-templates

    Write idiomatic Ruby code with metaprogramming, Rails patterns, and performance optimization.

    33k GitHub starsUsed in 8 repos~445 tokens
    DevelopmentAuto-check passed
  • Dhh Rails Style

    davekilleen/Dex

    This skill should be used when writing Ruby and Rails code in DHH's distinctive 37signals style.

    494 GitHub starsUsed in 1 repo~1.7k tokens
    DevelopmentAuto-check passed
  • Flowfile Debugging Playbook

    Edwardvaneechoud/Flowfile

    Symptom-to-cause triage playbook for Flowfile (core/worker/kernel/frontend/AI) — covers "no such table" DB cascades (two distinct causes), import-time Alembic migration corruption, silent…

    385 GitHub stars~6.3k tokensUpdated today
    DevelopmentAuto-check passed

More from antiwork/gumroad

  • Review PR

    antiwork/gumroad

    Review GitHub pull requests for the Gumroad codebase against project guidelines, code quality, and correctness.

    9.8k GitHub stars~1.2k tokensUpdated today
    Auto-check passed
  • Email Blast

    antiwork/gumroad

    Send one-off email blasts to Gumroad creators directly via production console, no PR or deploy needed.

    9.8k GitHub stars~1.4k tokensUpdated today
    Auto-check passed
  • Commit

    antiwork/gumroad

    Stage and commit changes with a clear, concise commit message.

    9.8k GitHub stars~503 tokensUpdated today
    Auto-check passed
  • Create Issue

    antiwork/gumroad

    Draft GitHub issues for the Gumroad codebase. An agent skill from antiwork/gumroad.

    9.8k GitHub stars~747 tokensUpdated today
    Auto-check passed
  • Test Confidence

    antiwork/gumroad

    AI-driven test execution. An agent skill from antiwork/gumroad.

    9.8k GitHub stars~738 tokensUpdated today
    Auto-check: notes

Works with

Questions about Gumroad Prod Console

What does Gumroad Prod Console do?

Execute read-only Ruby/Rails commands against Gumroad's production database for debugging and investigation. Gumroad Prod Console is an agent skill from antiwork/gumroad. Execute read-only Ruby/Rails commands against Gumroad's production database for debugging and investigation.

When should I use Gumroad Prod Console?

Gumroad Prod Console fits situations like: the user needs to debug production issues; investigate user reports; query production state; : check in prod.

How do I install Gumroad Prod Console in Claude Code?

Run `npx skills add antiwork/gumroad --skill gumroad-prod-console -a claude-code`. Or copy the skill folder (.agents/skills/gumroad-prod-console in antiwork/gumroad) into .claude/skills/gumroad-prod-console in your project. Claude Code loads it when a task matches its description.

How do I install Gumroad Prod Console in Codex?

Run `npx skills add antiwork/gumroad --skill gumroad-prod-console -a codex`. Or copy the skill folder (.agents/skills/gumroad-prod-console in antiwork/gumroad) into .agents/skills/gumroad-prod-console in your project. Codex loads it when a task matches its description.

Can I use Gumroad Prod Console in Cursor, Gemini CLI or GitHub Copilot?

Cursor, Gemini CLI, GitHub Copilot and OpenCode also load SKILL.md folders. With the skills CLI, run `npx skills add antiwork/gumroad --skill gumroad-prod-console -a cursor` (or -a gemini-cli, github-copilot or opencode for the others). To copy it by hand, put the folder in .cursor/skills/gumroad-prod-console, .gemini/skills/gumroad-prod-console, .github/skills/gumroad-prod-console and .opencode/skills/gumroad-prod-console in your project.

What does Gumroad Prod Console need to run?

Going by SKILL.md and its folder, Gumroad Prod Console needs a shell and Ruby for the scripts in its folder and the command-line tools its instructions call (bash and rails). Our summary lists: A Bash shell; Docker.

Does Gumroad Prod Console access the network?

SKILL.md contains no URLs. Any network use would come from the scripts or tools the agent runs. This is read from the text; nothing was executed.

Is Gumroad Prod Console safe to install?

Our automated static check of SKILL.md found notes only (mentions a .env file), nothing it rates as a warning. It is not a guarantee. The check reads SKILL.md only: the scripts in the folder are not scanned, so read them before running anything.

What licence does Gumroad Prod Console use?

Gumroad Prod Console is published under the MIT licence (the repository's licence). It allows redistribution, so the full SKILL.md is shown on this page.

How many tokens does Gumroad Prod Console use?

About 2.9k tokens (SKILL.md is roughly 12k characters). Agents keep only the skill's name and description in context until a task matches; then they load SKILL.md in full. Its references folder adds about 358 tokens, read only when the agent opens those files.

What are the alternatives to Gumroad Prod Console?

Skills that share tags, products or a category with Gumroad Prod Console: Production Log Inspection (bikeindex/bike_index, 308 stars), Rails (ericrisco/rsc-harness, 180 stars), Dhh (marckohlbrugge/37signals-skills, 724 stars) and Ruby Pro (davila7/claude-code-templates, 33k stars). The comparison table on this page puts their stars, adoption, token cost, safety result and licence side by side.

Who maintains Gumroad Prod Console?

antiwork (a GitHub organization) maintains it in antiwork/gumroad, which has 9,835 GitHub stars. The repository holds 6 skills in this directory. The repository was last updated on October 10, 2026.

Source: antiwork/gumroad on GitHub. Facts on this page come from the repository at the commit we read; the author's words are quoted as theirs.