All integrations

Ruby gem

Rails ActiveJobs, Sidekiq workers, Rake tasks.

LiveSDKchirp login

Pure Ruby gem - zero runtime deps beyond stdlib (`net/http`, `json`). `Chirp.track(name:) { |agent| ... }` is the canonical pattern: opens an activity, yields the agent to the block, closes on block exit. Block exceptions close the activity red automatically.

Designed for the three places long-running Ruby code lives: ActiveJobs (Rails), Sidekiq workers, and Rake tasks. Each pattern has a one-liner - see steps below.

Prerequisites

  • Ruby 3.0+.
  • A Chirp account.

Setup

  1. 1

    Install the gem

    Either bundle it or install globally.

    shell
    # Gemfile
    gem "chirp", "~> 0.5"
    
    # OR globally
    # gem install chirp
  2. 2

    Pair your laptop / server

    chirp login writes ~/.chirp/credentials. For Heroku / Render / Railway-style deploys without an interactive shell, set CHIRP_API_KEY as a config var instead - the SDK falls back to the env var.

    shell
    chirp login   # or: export CHIRP_API_KEY=chirp_sk_...
  3. 3

    Wrap a Sidekiq job

    Block-based API drops into Sidekiq's perform method cleanly. The agent ID is automatic; no class-level setup.

    app/workers/nightly_backup_worker.rb
    require "chirp"
    
    class NightlyBackupWorker
      include Sidekiq::Worker
    
      def perform
        Chirp.track(name: "nightly backup", schema: "@agent") do |agent|
          agent.update("dumping postgres")
          Backup.run!
    
          agent.update("uploading to S3")
          S3.upload!
        end
      end
    end
  4. 4

    Wrap a Rake task

    Same pattern. Rake task description doubles as the activity name.

    lib/tasks/migrate.rake
    namespace :db do
      desc "Backfill v3 schema"
      task backfill_v3: :environment do
        Chirp.track(name: "db:backfill_v3") do |agent|
          User.find_each.with_index do |user, i|
            user.migrate_to_v3!
            agent.update("user #{i + 1}/#{User.count}") if (i % 1000).zero?
          end
        end
      end
    end
  5. 5

    Wrap an ActiveJob

    ActiveJob is more convention-driven - you can monkey-patch perform_now / perform_later if you want every job tracked, or just wrap individual jobs. Recommended: wrap individually so you control which jobs are noisy.

What you’ll see

Card header: Ruby diamond logo + "Ruby · WORKING" + agent name. Action line shows the most recent `update()` argument. Closes green on block exit, red on block raise (with the exception class + message). Sidekiq retries: each retry opens a new card by default; pass `key: jid` to coalesce on the Sidekiq job ID so retries share a single card.

Troubleshooting

Net::OpenTimeout in production but works locally.
Production hosts often block outbound HTTPS by default. Whitelist api.chirpapp.dev in your egress rules. The SDK has a 5s connect timeout to fail fast if the network is wrong.
Activity stuck "working" after Sidekiq job dies (segfault, kill -9).
Sidekiq's hard-kill doesn't run finalizers. The activity auto-expires after 4h. To avoid the 4h hangtime, pair Sidekiq with Sidekiq::DeathHandlers - call Chirp.client.end(activity_id, outcome: :failure) in the death handler.
I want to track Sidekiq's whole queue, not individual jobs.
Add a Sidekiq middleware that wraps every perform with Chirp.track. The gem's README has a copy-paste middleware snippet.