meerkat-agents 0.1.1 → 0.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 54ba46da11751ebb2b4dc36e5c02c9ef99add0b0507822637a7ad343f97498ff
4
- data.tar.gz: edeb9fc5d5c08e3b44263460ace6591ebf81ec2187477cb69e2d0b1069df2925
3
+ metadata.gz: '0151964121201f009fe0a38729a847a3b45e7ba6521f10a374936f563fcdef17'
4
+ data.tar.gz: 31d8cd573baf1ff066769e8fa30564ac421828d1da6b4ef098aaf66b0758748a
5
5
  SHA512:
6
- metadata.gz: c6cad6d121752a4438682e854346b680781b916540cdf184b9556042326f865a4bda00ea3fa993010f59f6de762956dbe3be9d604a082f8cd202882ac6aa3bbf
7
- data.tar.gz: 6addcf95c8bab0591ec242814960bb79e54e9b97043cc85888aea0ebf4fc0628a3a751db0cedc756d1645e9712200e1e0a3046362c92e3a479a4afcba13017b6
6
+ metadata.gz: 13b749556fee04012ded622626e438e701afe51e0ae1d820ccfeb9f5e9136fb337317aa0c6f2464ad03205df67cdc1731c75226725b3d3b35354194e81eb6f62
7
+ data.tar.gz: f5e6b21b1aaeea6610af91bdf1f6edfa9b06c8880efa82ae02060c994ad9a4adfa51e5cea9bf1c544422b330ef6a0de8c394acb1fc761162a9cb04c26ee95d71
data/CHANGELOG.md CHANGED
@@ -5,6 +5,37 @@ All notable changes to this project will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [0.3.1] - 2026-07-17
9
+
10
+ ### Changed
11
+
12
+ - RubyGems summary/description rewritten around the problem, use cases, and how Meerkat differs from Sidekiq / Active Job / queue gems (no pricing copy)
13
+ - Homepage and documentation URIs point to https://cloud.meerkatagents.com/docs/introduction
14
+
15
+ ## [0.3.0] - 2026-07-16
16
+
17
+ ### Added
18
+
19
+ - `client.monitors` resource against `/api/v1/monitors` (create, list, retrieve, update, delete, pause, resume, run, runs, retrieve_run, artifacts, events)
20
+ - `client.tasks` remains as a deprecated alias of `client.monitors`
21
+
22
+ ### Changed
23
+
24
+ - Primary API surface is Change Intelligence **monitors** (always recurring; no `task_type` on create)
25
+ - README and gemspec copy updated for Cloud monitors + webhooks
26
+
27
+ ## [0.2.0] - 2026-07-09
28
+
29
+ ### Added
30
+
31
+ - `Meerkat::SubscriptionRequiredError` for HTTP 402 (free plan limits)
32
+ - Signup requires `company` and `website`
33
+
34
+ ### Changed
35
+
36
+ - RubyGems homepage and documentation URIs point to Cloud docs (`cloud.meerkatagents.com/docs/sdk-ruby`)
37
+ - README is Cloud-first: install → signup → LLM key → create monitor → subscribe
38
+
8
39
  ## [0.1.1] - 2026-06-27
9
40
 
10
41
  ### Changed
@@ -20,5 +51,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
20
51
  - Webhook HMAC-SHA256 verification helpers
21
52
  - Optional Rails railtie and webhook verification concern
22
53
 
54
+ [0.3.1]: https://github.com/Tiny-Bubble-Company/meerkat-ruby/releases/tag/v0.3.1
55
+ [0.3.0]: https://github.com/Tiny-Bubble-Company/meerkat-ruby/releases/tag/v0.3.0
56
+ [0.2.0]: https://github.com/Tiny-Bubble-Company/meerkat-ruby/releases/tag/v0.2.0
23
57
  [0.1.1]: https://github.com/Tiny-Bubble-Company/meerkat-ruby/releases/tag/v0.1.1
24
58
  [0.1.0]: https://github.com/Tiny-Bubble-Company/meerkat-ruby/releases/tag/v0.1.0
data/README.md CHANGED
@@ -1,410 +1,61 @@
1
- <p align="center">
2
- <a href="https://meerkatagents.com">
3
- <img src=".github/readme-banner.png" alt="Meerkat — open source webhook-native agent task API" width="100%">
4
- </a>
5
- </p>
6
-
7
- <p align="center">
8
- <img src=".github/meerkat-logo.png" alt="Meerkat mascot" width="88" height="88">
9
- <br>
10
- <em>Describe a task in plain English. Meerkat runs it async — results POST to your webhook.</em>
11
- </p>
12
-
13
1
  # meerkat-agents
14
2
 
15
- Official Ruby client for [Meerkat](https://github.com/Tiny-Bubble-Company/meerkat) an open source, webhook-native API for async agent tasks.
16
-
17
- Install as **`meerkat-agents`**, require as **`meerkat`**:
18
-
19
- ```ruby
20
- gem "meerkat-agents"
21
- # ...
22
- require "meerkat"
23
- ```
24
-
25
- [![Gem Version](https://badge.fury.io/rb/meerkat-agents.svg)](https://badge.fury.io/rb/meerkat-agents)
26
- [![License: MIT](https://img.shields.io/badge/License-MIT-111111.svg)](LICENSE)
27
-
28
- ---
29
-
30
- ## About Meerkat
31
-
32
- **Meerkat** is open source infrastructure for async agent tasks. You describe work in plain English, connect your own LLM key (BYOK), and Meerkat schedules execution and POSTs signed JSON to your webhook — without building schedulers, scrapers, or retry logic.
33
-
34
- | Resource | Link |
35
- |----------|------|
36
- | **Website** | [meerkatagents.com](https://meerkatagents.com) |
37
- | **Documentation** | [meerkatagents.com/docs](https://meerkatagents.com/docs) |
38
- | **Use cases** | [Package tracking](https://meerkatagents.com/use-cases/package-tracking) · [Site monitoring](https://meerkatagents.com/use-cases/website-monitoring) · [Agent webhooks](https://meerkatagents.com/use-cases/agent-webhooks) |
39
- | **Developer guides** | [meerkatagents.com/blog](https://meerkatagents.com/blog) |
40
- | **Sign up (Cloud)** | [cloud.meerkatagents.com/signup](https://cloud.meerkatagents.com/signup) |
41
- | **Open source server** | [github.com/Tiny-Bubble-Company/meerkat](https://github.com/Tiny-Bubble-Company/meerkat) |
42
-
43
- **This repo** is the official **Ruby gem** (`meerkat-agents` on RubyGems). For product overview, use cases, and self-host vs Cloud, read more on the [Meerkat website](https://meerkatagents.com).
44
-
45
- **Other SDKs:** [meerkat-python](https://github.com/Tiny-Bubble-Company/meerkat-python) · [meerkat-javascript](https://github.com/Tiny-Bubble-Company/meerkat-javascript)
46
-
47
- ---
48
-
49
- ## Table of contents
50
-
51
- - [About Meerkat](#about-meerkat)
52
- - [What is Meerkat?](#what-is-meerkat)
53
- - [What problem does it solve?](#what-problem-does-it-solve)
54
- - [Why use this gem?](#why-use-this-gem)
55
- - [How it works](#how-it-works)
56
- - [Use cases](#use-cases)
57
- - [Task types](#task-types)
58
- - [Self-host vs Meerkat Cloud](#self-host-vs-meerkat-cloud)
59
- - [Installation](#installation)
60
- - [Quick start](#quick-start)
61
- - [Examples](#examples)
62
- - [Receiving webhooks (Rails)](#receiving-webhooks-rails)
63
- - [Output formats](#output-formats)
64
- - [API reference](#api-reference)
65
- - [Configuration](#configuration)
66
- - [Development](#development)
67
- - [License](#license)
68
-
69
- ---
70
-
71
- ## What is Meerkat?
72
-
73
- Meerkat gives developers a single primitive for agentic async work:
74
-
75
- ```
76
- Register a task → Meerkat runs it → findings POST to your webhook
77
- ```
78
-
79
- Describe a task in plain English, pass structured `input_params`, bring your own LLM key (BYOK), and Meerkat's agent executes the work — fetching webpages, extracting structured findings, and delivering JSON to your `output_webhook` on a schedule or on demand.
80
-
81
- **No polling. No per-carrier SDKs. No LLM tool loops to maintain.**
82
-
83
- This gem wraps the Meerkat REST API so you can create tasks, trigger runs, and verify inbound webhooks from Ruby and Rails apps without hand-rolling HTTP clients.
84
-
85
- ---
86
-
87
- ## What problem does it solve?
88
-
89
- Building async agent workflows usually means stitching together:
90
-
91
- - A job queue and scheduler
92
- - LLM calls with tool use (fetch URL, parse HTML, compare state)
93
- - Webhook delivery and retry logic
94
- - Change detection between runs
95
-
96
- Meerkat handles all of that as a managed API. **meerkat-agents** handles the client side:
97
-
98
- | Without the gem | With meerkat-agents |
99
- |-----------------|-------------------|
100
- | Raw `curl` / Faraday calls | Typed resource methods (`client.tasks.create`, `client.tasks.run`) |
101
- | Manual auth headers | API key configured once |
102
- | DIY webhook HMAC verification | `Meerkat::Webhooks.verify` + Rails concern |
103
- | Error parsing by hand | `Meerkat::NotFoundError`, `ValidationError`, etc. |
104
-
105
- ---
106
-
107
- ## Why use this gem?
108
-
109
- - **Webhook-native** — every task delivers JSON to your endpoint; the gem helps you verify signatures
110
- - **BYOK** — Anthropic, OpenAI, OpenRouter, or Grok; keys stored on your Meerkat account
111
- - **Recurring + one-off** — natural-language schedules (`every 2 hours`) or ad-hoc runs
112
- - **Self-host or Cloud** — same API against Docker, Render, Fly.io, or [Meerkat Cloud](https://cloud.meerkatagents.com/signup)
113
- - **Rails-ready** — optional railtie, env-based config, webhook verification concern
114
-
115
- ---
116
-
117
- ## How it works
118
-
119
- ```
120
- ┌─────────────┐ client.tasks.create ┌─────────────┐ agent + tools ┌─────────────┐
121
- │ Your app │ ───────────────────────► │ Meerkat │ ──────────────────► │ Web / APIs │
122
- └─────────────┘ └─────────────┘ └─────────────┘
123
- ▲ │
124
- │ POST output_webhook │
125
- └──────────────────────────────────────────┘
126
- (verify with Meerkat::Webhooks)
127
- ```
128
-
129
- | Step | What happens |
130
- |------|--------------|
131
- | **1. Register** | `client.tasks.create(...)` — describe work, pass params, set webhook |
132
- | **2. Run** | Meerkat schedules recurring tasks or runs one-offs on demand |
133
- | **3. Receive** | Findings POSTed to your webhook as structured JSON |
134
-
135
- ---
136
-
137
- ## Use cases
138
-
139
- What teams ship with Meerkat — aligned with the [use cases on meerkatagents.com](https://meerkatagents.com):
140
-
141
- | Use case | In one line | On the website |
142
- |----------|-------------|----------------|
143
- | **Package tracking** | Webhook when DHL, UPS, FedEx, or any carrier status changes | [Package tracking →](https://meerkatagents.com/use-cases/package-tracking) |
144
- | **Website monitoring** | Watch a URL; get notified when the signal you describe happens | [Site monitoring →](https://meerkatagents.com/use-cases/website-monitoring) |
145
- | **Price & stock** | Competitor price drops and restocks without building a scraper | [Guide →](https://meerkatagents.com/blog/competitor-price-stock-monitoring) |
146
- | **Async agent webhooks** | Register LLM agent work; results POST to your endpoint | [Agent webhooks →](https://meerkatagents.com/use-cases/agent-webhooks) |
147
-
148
- Read the full [developer guides](https://meerkatagents.com/blog) for step-by-step tutorials with API examples.
149
-
150
- ---
151
-
152
- ### Package tracking — webhook when status changes
153
-
154
- Monitor any courier tracking link — DHL, UPS, FedEx, USPS, DPD, Royal Mail — with **one API**. Meerkat's agent reads the carrier page on a schedule, detects state changes, and POSTs structured JSON to your endpoint. No per-carrier SDKs, no polling loops, no LLM tool code to maintain.
155
-
156
- - **Every carrier, one endpoint** — pass a `courier_tracking_link`; adding a new carrier is zero integration code.
157
- - **Webhook on change only** — hear from Meerkat when status moves (*In transit → Out for delivery → Delivered*), not on every poll.
158
- - **Signed and retried** — HMAC-SHA256 signatures, exponential backoff, delivery history via the events API.
159
-
160
- ```ruby
161
- client.tasks.create(
162
- task_type: "recurring",
163
- description: "Monitor DHL tracking and report status changes",
164
- input_params: { courier_tracking_link: "https://www.dhl.de/track?id=..." },
165
- frequency: "every 2 hours",
166
- output_webhook: "https://your-app.com/webhooks/meerkat"
167
- )
168
- ```
169
-
170
- → [Package tracking use case](https://meerkatagents.com/use-cases/package-tracking) · [Shipment tracking guide](https://meerkatagents.com/blog/shipment-tracking-api-webhook)
171
-
172
- ---
173
-
174
- ### Website monitoring — watch any URL
175
-
176
- A change-detection API that understands **intent**, not just pixel diffs. Describe the signal in plain English — *price under $99*, *plan name changed*, *status page updated* — and Meerkat watches on a schedule. It only fires your webhook when that condition is met.
177
-
178
- - **Semantic, not cosmetic diff** — no CSS selectors to maintain when the page layout shifts.
179
- - **JS-rendered pages** — SPAs and dynamic content via headless fetch before reasoning.
180
- - **Your schedule** — natural language (`every 15 minutes`), cron, or on-demand `client.tasks.run(id)`.
181
-
182
- ```ruby
183
- client.tasks.create(
184
- task_type: "recurring",
185
- description: "Notify me when this product drops below $99",
186
- input_params: { url: "https://shop.example.com/widget-pro" },
187
- frequency: "every 30 minutes",
188
- output_webhook: "https://your-app.com/webhooks/meerkat"
189
- )
190
- ```
191
-
192
- → [Website monitoring use case](https://meerkatagents.com/use-cases/website-monitoring) · [Monitor website for changes guide](https://meerkatagents.com/blog/monitor-website-for-changes)
193
-
194
- ---
195
-
196
- ### Price & stock monitoring — competitor alerts
197
-
198
- Track competitor product pages and get a signed webhook when **price drops**, **price increases**, or **stock flips** (out of stock → in stock). One task per SKU — no scraper fleet, scheduler, or retry layer to operate.
199
-
200
- ```ruby
201
- client.tasks.create(
202
- task_type: "recurring",
203
- description: "Report price and stock whenever either changes",
204
- input_params: { url: "https://competitor.com/product/sku-123" },
205
- frequency: "every 15 minutes",
206
- output_webhook: "https://your-app.com/webhooks/meerkat"
207
- )
208
- ```
209
-
210
- Example webhook when price moves:
211
-
212
- ```json
213
- {
214
- "data": {
215
- "summary": "Price dropped from 99.00 to 89.00",
216
- "findings": { "price": 89.0, "previous_price": 99.0, "in_stock": true },
217
- "change_detected": true
218
- }
219
- }
220
- ```
221
-
222
- → [Competitor price & stock guide](https://meerkatagents.com/blog/competitor-price-stock-monitoring)
223
-
224
- ---
225
-
226
- ### Async agent webhooks — skip the scheduler boilerplate
227
-
228
- Meerkat is the open source primitive for engineers who would rather ship product than rebuild **schedulers, LLM tool loops, retries, and signed webhook delivery**. Register a task in plain English, attach your LLM key (BYOK), point at an endpoint — done.
229
-
230
- - **One verb: register** — `POST /tasks` creates recurring or one-off agent work.
231
- - **Webhook-native results** — structured JSON, signed, retried until 2xx (same contract as Stripe or GitHub webhooks).
232
- - **MIT & self-hostable** — Docker, Render, Fly.io, or Meerkat Cloud; identical REST API.
233
-
234
- ```ruby
235
- client.tasks.create(
236
- task_type: "recurring",
237
- description: "Summarize new arXiv papers in distributed systems",
238
- input_params: { topic: "distributed systems" },
239
- frequency: "0 9 * * *",
240
- output_webhook: "https://your-app.com/webhooks/meerkat"
241
- )
242
- ```
243
-
244
- → [Agent webhooks use case](https://meerkatagents.com/use-cases/agent-webhooks) · [Webhook vs polling guide](https://meerkatagents.com/blog/webhook-vs-polling)
245
-
246
- ---
247
-
248
- ### One-off lookups
249
-
250
- Ad-hoc agent tasks without standing up a schedule — research, single URL extraction, or on-demand runs triggered from your app:
251
-
252
- ```ruby
253
- client.tasks.create(
254
- task_type: "one_off",
255
- description: "Fetch the current price of this product once",
256
- input_params: { url: "https://example.com/product/123" },
257
- output_webhook: "https://your-app.com/webhooks/meerkat"
258
- )
259
- ```
260
-
261
- ---
262
-
263
- ### Scheduled scraping with webhooks
264
-
265
- Need data on a cadence, not just change detection? Set a frequency and receive structured findings every run — see the [web scraping API guide](https://meerkatagents.com/blog/web-scraping-api-scheduled-webhooks).
266
-
267
- ---
268
-
269
- ## Task types
270
-
271
- | Type | Behavior | Best for |
272
- |------|----------|----------|
273
- | `recurring` | Runs on a schedule; compares state between runs; reports changes | Courier tracking, uptime, price watches |
274
- | `one_off` | Runs once, reports findings, marks task complete | Ad-hoc research, single lookups |
275
-
276
- **Frequency** accepts natural language (`every 30 minutes`, `hourly`, `every 2 hours`) or cron expressions. Required for `recurring` tasks; omit for `one_off`.
277
-
278
- ---
279
-
280
- ## Self-host vs Meerkat Cloud
281
-
282
- | | Self-host (OSS) | Meerkat Cloud |
283
- |--|-----------------|---------------|
284
- | **API** | Identical | Identical |
285
- | **LLM keys** | You supply (BYOK) | You supply (BYOK) |
286
- | **Infra / ops** | You run Postgres + workers | Managed for you |
287
- | **Base URL** | `http://localhost:3000/api/v1` | `https://cloud.meerkatagents.com/api/v1` (default) |
288
-
289
- LLM usage is always billed by **your provider**. Meerkat never sees your model costs.
290
-
291
- Self-host: [meerkat README — Docker](https://github.com/Tiny-Bubble-Company/meerkat#getting-started--docker-recommended)
292
-
293
- ---
294
-
295
- ## Installation
296
-
297
- Add to your Gemfile:
298
-
299
- ```ruby
300
- gem "meerkat-agents"
301
- ```
302
-
303
- Or install directly:
3
+ Change Intelligence for Ruby. Create monitors, inspect runs and artifacts, receive signed webhooks.
304
4
 
305
5
  ```bash
306
6
  gem install meerkat-agents
307
7
  ```
308
8
 
309
- Then in your app:
310
-
311
9
  ```ruby
312
10
  require "meerkat"
313
11
  ```
314
12
 
13
+ Default API base: `https://cloud.meerkatagents.com/api/v1`
14
+
315
15
  ---
316
16
 
317
17
  ## Quick start
318
18
 
319
- ### 1. Get an API key
320
-
321
- Sign up via the [Meerkat Cloud dashboard](https://cloud.meerkatagents.com/signup) or programmatically:
322
-
323
- ```ruby
324
- require "meerkat"
19
+ ### 1. Sign up
325
20
 
326
- client = Meerkat::Client.new(base_url: "https://cloud.meerkatagents.com/api/v1")
327
- result = client.signup.create(email: "you@company.com", name: "Your Name")
328
- api_key = result.dig("data", "api_key") # store securely — shown once
329
- ```
21
+ [cloud.meerkatagents.com/signup](https://cloud.meerkatagents.com/signup) — copy `MEERKAT_API_KEY`, add your LLM key under **LLM key**.
330
22
 
331
- ### 2. Create a task
23
+ ### 2. Create a monitor
332
24
 
333
25
  ```ruby
334
26
  client = Meerkat::Client.new(api_key: ENV["MEERKAT_API_KEY"])
335
27
 
336
- response = client.tasks.create(
337
- task_type: "recurring",
338
- description: "Monitor courier tracking and notify on status changes",
339
- input_params: { courier_tracking_link: "https://..." },
340
- frequency: "every 2 hours",
341
- output_webhook: "https://your-app.com/webhooks/meerkat"
342
- )
343
-
344
- task = response["data"]
345
- ```
346
-
347
- ### 3. Trigger a run (optional)
348
-
349
- ```ruby
350
- client.tasks.run(task["id"], async: true)
351
- ```
352
-
353
- ---
354
-
355
- ## Examples
356
-
357
- ### List and filter tasks
358
-
359
- ```ruby
360
- client.tasks.list(status: "active", task_type: "recurring", limit: 20)
361
- client.tasks.retrieve(1)
362
- client.tasks.pause(1)
363
- client.tasks.resume(1)
364
- client.tasks.delete(1)
365
- ```
366
-
367
- ### One-off lookup
368
-
369
- ```ruby
370
- client.tasks.create(
371
- task_type: "one_off",
372
- description: "Fetch the current price of this product",
373
- input_params: { url: "https://example.com/product/123" },
374
- output_webhook: "https://your-app.com/webhooks/meerkat"
28
+ client.monitors.create(
29
+ description: "Notify me when pricing or plan limits change",
30
+ input_params: { url: "https://competitor.com/pricing" },
31
+ frequency: "every 6 hours",
32
+ output_webhook: "https://myapp.com/webhooks/meerkat"
375
33
  )
376
34
  ```
377
35
 
378
- ### Inspect runs and webhook delivery history
36
+ All monitors are recurring. There is no `task_type`.
379
37
 
380
- ```ruby
381
- client.tasks.runs(1, limit: 10)
382
- client.tasks.events(1, limit: 50)
383
- ```
384
-
385
- ### API keys
38
+ ### 3. List / update / delete
386
39
 
387
40
  ```ruby
388
- client.api_keys.list
389
- client.api_keys.create(name: "Production")
390
- client.api_keys.revoke(key_id)
41
+ client.monitors.list
42
+ client.monitors.retrieve(id)
43
+ client.monitors.update(id, frequency: "every 12 hours")
44
+ client.monitors.pause(id)
45
+ client.monitors.resume(id)
46
+ client.monitors.delete(id)
391
47
  ```
392
48
 
393
- ---
394
-
395
- ## Receiving webhooks (Rails)
396
-
397
- Every outbound POST is HMAC-SHA256 signed in the `X-Meerkat-Signature` header. Verify before processing:
49
+ ### 4. Runs & artifacts
398
50
 
399
51
  ```ruby
400
- Meerkat::Webhooks.verify(
401
- payload: request.raw_post,
402
- signature: request.headers["X-Meerkat-Signature"],
403
- secret: ENV["MEERKAT_WEBHOOK_SECRET"]
404
- )
52
+ client.monitors.runs(id)
53
+ client.monitors.retrieve_run(id, run_id)
54
+ client.monitors.artifacts(id, run_id) # structured findings from the run
55
+ client.monitors.run(id) # trigger an on-demand run
405
56
  ```
406
57
 
407
- ### Rails controller concern
58
+ ### 5. Webhooks in Rails
408
59
 
409
60
  ```ruby
410
61
  class Webhooks::MeerkatController < ApplicationController
@@ -412,120 +63,33 @@ class Webhooks::MeerkatController < ApplicationController
412
63
 
413
64
  def create
414
65
  payload = JSON.parse(request.raw_post)
415
- # handle event: run_completed, status_changed, etc.
416
66
  head :ok
417
67
  end
418
68
  end
419
69
  ```
420
70
 
421
- Set `MEERKAT_WEBHOOK_SECRET` in your environment.
422
-
423
- ---
424
-
425
- ## Output formats
426
-
427
- `output_webhook` is required on every task (or use `"default"` if your account has a default webhook configured). `output_format` is optional.
428
-
429
- | Preset | Webhook payload shape |
430
- |--------|----------------------|
431
- | `default` | `{ event, task_id, task_run_id, occurred_at, data: { summary, findings, change_detected, ... } }` |
432
- | `compact` | Top-level `summary`, `change_detected`, `findings` |
433
- | `flat` | Findings merged into the webhook root object |
434
- | `findings_only` | Findings object only |
435
- | `minimal` | `event`, `task_id`, `summary`, `change_detected` |
436
-
437
- ```ruby
438
- client.tasks.create(
439
- description: "...",
440
- input_params: { url: "https://..." },
441
- output_webhook: "https://your-app.com/hook",
442
- output_format: "flat"
443
- )
444
- ```
445
-
446
- Any other string is passed to the agent as a custom instruction for shaping findings (max 500 chars).
447
-
448
- ---
449
-
450
- ## API reference
451
-
452
- Default base URL: `https://cloud.meerkatagents.com/api/v1`
453
-
454
- All endpoints except signup require `Authorization: Bearer mk_...`.
455
-
456
- | SDK method | HTTP | Description |
457
- |------------|------|-------------|
458
- | `client.signup.create(...)` | `POST /signup` | Create account + API key |
459
- | `client.api_keys.list` | `GET /api_keys` | List API keys |
460
- | `client.api_keys.create(name:)` | `POST /api_keys` | Generate a new key |
461
- | `client.api_keys.revoke(id)` | `DELETE /api_keys/:id` | Revoke a key |
462
- | `client.tasks.list(...)` | `GET /tasks` | List tasks |
463
- | `client.tasks.create(...)` | `POST /tasks` | Create a task |
464
- | `client.tasks.retrieve(id)` | `GET /tasks/:id` | Task details + last known state |
465
- | `client.tasks.update(id, ...)` | `PATCH /tasks/:id` | Partial update |
466
- | `client.tasks.replace(id, ...)` | `PUT /tasks/:id` | Full replace |
467
- | `client.tasks.delete(id)` | `DELETE /tasks/:id` | Archive or delete |
468
- | `client.tasks.run(id, async:)` | `POST /tasks/:id/run` | Trigger on-demand run |
469
- | `client.tasks.pause(id)` | `POST /tasks/:id/pause` | Pause recurring task |
470
- | `client.tasks.resume(id)` | `POST /tasks/:id/resume` | Resume recurring task |
471
- | `client.tasks.runs(id)` | `GET /tasks/:id/runs` | Run history |
472
- | `client.tasks.events(id)` | `GET /tasks/:id/events` | Webhook delivery log |
473
-
474
- Full OpenAPI spec: [`meerkat/openapi/openapi.yaml`](https://github.com/Tiny-Bubble-Company/meerkat/blob/main/openapi/openapi.yaml)
71
+ Set `MEERKAT_WEBHOOK_SECRET`.
475
72
 
476
73
  ---
477
74
 
478
75
  ## Configuration
479
76
 
480
- ### Environment variables
481
-
482
77
  | Variable | Description |
483
78
  |----------|-------------|
484
- | `MEERKAT_API_KEY` | API key from signup (`mk_...`) |
485
- | `MEERKAT_BASE_URL` | API base URL (default: Meerkat Cloud) |
486
- | `MEERKAT_WEBHOOK_SECRET` | Secret for verifying inbound webhooks |
487
-
488
- ### Rails / global config
489
-
490
- ```ruby
491
- Meerkat.configure do |config|
492
- config.api_key = ENV["MEERKAT_API_KEY"]
493
- config.base_url = ENV.fetch("MEERKAT_BASE_URL", Meerkat::Client::DEFAULT_BASE_URL)
494
- end
495
-
496
- Meerkat.configuration.client.tasks.list(status: "active")
497
- ```
498
-
499
- ### Self-hosted instance
500
-
501
- ```ruby
502
- client = Meerkat::Client.new(
503
- api_key: ENV["MEERKAT_API_KEY"],
504
- base_url: "http://localhost:3000/api/v1"
505
- )
506
- ```
79
+ | `MEERKAT_API_KEY` | From Cloud signup |
80
+ | `MEERKAT_WEBHOOK_SECRET` | HMAC verification |
81
+ | `MEERKAT_BASE_URL` | Optional; defaults to Cloud |
507
82
 
508
83
  ---
509
84
 
510
- ## Development
511
-
512
- ```bash
513
- bundle install
514
- bundle exec rake spec
515
- ```
516
-
517
- See [PUBLISHING.md](PUBLISHING.md) for local testing and RubyGems release steps.
518
-
519
- ---
85
+ ## Pricing
520
86
 
521
- ## Related projects
87
+ Free: 1 monitor · 1 run. Then [$20 — 5 monitors, 50 runs](https://cloud.meerkatagents.com/subscribe).
522
88
 
523
- - [meerkat](https://github.com/Tiny-Bubble-Company/meerkat) open source API server
524
- - [meerkat-python](https://github.com/Tiny-Bubble-Company/meerkat-python) — Python SDK
525
- - [meerkat-javascript](https://github.com/Tiny-Bubble-Company/meerkat-javascript) — JavaScript/TypeScript SDK
89
+ Limit hit `Meerkat::SubscriptionRequiredError`.
526
90
 
527
91
  ---
528
92
 
529
- ## License
93
+ ## Docs
530
94
 
531
- MIT — see [LICENSE](LICENSE).
95
+ https://cloud.meerkatagents.com/docs/introduction
@@ -19,8 +19,13 @@ module Meerkat
19
19
  @signup ||= Resources::Signup.new(self)
20
20
  end
21
21
 
22
+ def monitors
23
+ @monitors ||= Resources::Monitors.new(self)
24
+ end
25
+
26
+ # Deprecated: use {#monitors}. Kept for older examples.
22
27
  def tasks
23
- @tasks ||= Resources::Tasks.new(self)
28
+ monitors
24
29
  end
25
30
 
26
31
  def api_keys
@@ -90,6 +95,8 @@ module Meerkat
90
95
  body
91
96
  when 401
92
97
  raise AuthenticationError.new(error_detail(body), status: 401, errors: body&.dig("errors"))
98
+ when 402
99
+ raise SubscriptionRequiredError.new(error_detail(body), status: 402, errors: body&.dig("errors"))
93
100
  when 404
94
101
  raise NotFoundError.new(error_detail(body), status: 404, errors: body&.dig("errors"))
95
102
  when 422
data/lib/meerkat/error.rb CHANGED
@@ -14,5 +14,6 @@ module Meerkat
14
14
  class AuthenticationError < Error; end
15
15
  class NotFoundError < Error; end
16
16
  class ValidationError < Error; end
17
+ class SubscriptionRequiredError < Error; end
17
18
  class ApiError < Error; end
18
19
  end
@@ -0,0 +1,74 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Meerkat
4
+ module Resources
5
+ # Change Intelligence monitors — always recurring.
6
+ # CRUD + runs/artifacts against /api/v1/monitors.
7
+ class Monitors < Base
8
+ def list(status: nil, include_archived: nil, limit: nil, offset: nil)
9
+ client.get("/monitors", params: {
10
+ status: status,
11
+ include_archived: include_archived,
12
+ limit: limit,
13
+ offset: offset
14
+ }.compact)
15
+ end
16
+
17
+ def retrieve(id)
18
+ client.get("/monitors/#{id}")
19
+ end
20
+
21
+ def create(**attributes)
22
+ client.post("/monitors", body: { monitor: public_attrs(attributes) })
23
+ end
24
+
25
+ def update(id, **attributes)
26
+ client.patch("/monitors/#{id}", body: { monitor: public_attrs(attributes) })
27
+ end
28
+
29
+ def replace(id, **attributes)
30
+ client.put("/monitors/#{id}", body: { monitor: public_attrs(attributes) })
31
+ end
32
+
33
+ def delete(id, permanent: false)
34
+ client.delete("/monitors/#{id}", params: { permanent: permanent })
35
+ end
36
+
37
+ def run(id, async: true)
38
+ client.post("/monitors/#{id}/run", params: { async: async })
39
+ end
40
+
41
+ def pause(id)
42
+ client.post("/monitors/#{id}/pause")
43
+ end
44
+
45
+ def resume(id)
46
+ client.post("/monitors/#{id}/resume")
47
+ end
48
+
49
+ def runs(id, limit: nil)
50
+ client.get("/monitors/#{id}/runs", params: { limit: limit }.compact)
51
+ end
52
+
53
+ def retrieve_run(id, run_id)
54
+ client.get("/monitors/#{id}/runs/#{run_id}")
55
+ end
56
+
57
+ def artifacts(id, run_id)
58
+ client.get("/monitors/#{id}/runs/#{run_id}/artifacts")
59
+ end
60
+
61
+ def events(id, limit: nil)
62
+ client.get("/monitors/#{id}/events", params: { limit: limit }.compact)
63
+ end
64
+
65
+ private
66
+
67
+ def public_attrs(attributes)
68
+ attributes = attributes.transform_keys(&:to_sym)
69
+ attributes.delete(:task_type)
70
+ attributes
71
+ end
72
+ end
73
+ end
74
+ end
@@ -3,12 +3,13 @@
3
3
  module Meerkat
4
4
  module Resources
5
5
  class Signup < Base
6
- def create(email:, name: nil, company: nil)
6
+ def create(email:, company:, website:, name: nil)
7
7
  client.post("/signup", body: {
8
8
  customer: {
9
9
  email: email,
10
10
  name: name,
11
- company: company
11
+ company: company,
12
+ website: website
12
13
  }.compact
13
14
  })
14
15
  end
@@ -2,55 +2,12 @@
2
2
 
3
3
  module Meerkat
4
4
  module Resources
5
- class Tasks < Base
6
- def list(task_type: nil, status: nil, include_archived: nil, limit: nil, offset: nil)
7
- client.get("/tasks", params: {
8
- task_type: task_type,
9
- status: status,
10
- include_archived: include_archived,
11
- limit: limit,
12
- offset: offset
13
- }.compact)
14
- end
15
-
16
- def retrieve(id)
17
- client.get("/tasks/#{id}")
18
- end
19
-
5
+ # @deprecated Use {Monitors} (`client.monitors`) instead.
6
+ # Delegates to the monitors API for backward compatibility.
7
+ class Tasks < Monitors
20
8
  def create(**attributes)
21
- client.post("/tasks", body: { task: attributes })
22
- end
23
-
24
- def update(id, **attributes)
25
- client.patch("/tasks/#{id}", body: { task: attributes })
26
- end
27
-
28
- def replace(id, **attributes)
29
- client.put("/tasks/#{id}", body: { task: attributes })
30
- end
31
-
32
- def delete(id, permanent: false)
33
- client.delete("/tasks/#{id}", params: { permanent: permanent })
34
- end
35
-
36
- def run(id, async: true)
37
- client.post("/tasks/#{id}/run", params: { async: async })
38
- end
39
-
40
- def pause(id)
41
- client.post("/tasks/#{id}/pause")
42
- end
43
-
44
- def resume(id)
45
- client.post("/tasks/#{id}/resume")
46
- end
47
-
48
- def runs(id, limit: nil)
49
- client.get("/tasks/#{id}/runs", params: { limit: limit }.compact)
50
- end
51
-
52
- def events(id, limit: nil)
53
- client.get("/tasks/#{id}/events", params: { limit: limit }.compact)
9
+ # Old clients may still send task_type — strip and route to monitors.
10
+ super(**attributes)
54
11
  end
55
12
  end
56
13
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Meerkat
4
- VERSION = "0.1.1"
4
+ VERSION = "0.3.1"
5
5
  end
data/lib/meerkat.rb CHANGED
@@ -8,6 +8,7 @@ require_relative "meerkat/configuration"
8
8
  require_relative "meerkat/resources/base"
9
9
  require_relative "meerkat/resources/signup"
10
10
  require_relative "meerkat/resources/api_keys"
11
+ require_relative "meerkat/resources/monitors"
11
12
  require_relative "meerkat/resources/tasks"
12
13
 
13
14
  if defined?(Rails::Railtie)
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: meerkat-agents
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.1
4
+ version: 0.3.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Tiny Bubble Company
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2026-06-28 00:00:00.000000000 Z
11
+ date: 2026-07-17 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: faraday
@@ -31,13 +31,36 @@ dependencies:
31
31
  - !ruby/object:Gem::Version
32
32
  version: '3'
33
33
  description: |
34
- Meerkat is an open-source, webhook-native API for async agent tasks. Run background work similar to
35
- Sidekiq — register a job and walk away — but describe the task in plain English and Meerkat understands
36
- what to do and acts accordingly (fetch pages, extract data, compare state, retry on failure). Monitor
37
- any website for changes, track shipments, watch competitor prices and stock, or schedule recurring
38
- scraping jobs and get an HMAC-signed webhook when something happens. Bring your own LLM key
39
- (OpenAI, Anthropic, OpenRouter, Grok, or open-source models via compatible providers) no schedulers
40
- or webhook plumbing to build yourself.
34
+ Meerkat Agents is the official Ruby client for Meerkat Cloud Change Intelligence.
35
+
36
+ Problem it solves
37
+ -----------------
38
+ Rails apps often need to know when something on the web changes competitor pricing,
39
+ plan pages, package tracking, stock, or content without building scrapers, cron jobs,
40
+ HTML diffs, retries, and webhook plumbing. Meerkat runs that watch loop in the cloud and
41
+ POSTs structured change events to your Rails app.
42
+
43
+ How it differs from Sidekiq / Active Job / Good Job / Solid Queue / Delayed Job / Resque
44
+ ----------------------------------------------------------------------------------------
45
+ Those gems are excellent for running YOUR Ruby jobs on YOUR workers (background jobs,
46
+ queues, cron). Meerkat is not a job queue. You describe what to watch in plain English;
47
+ Meerkat fetches sources, uses your LLM key (BYOK) to judge meaningful change, and delivers
48
+ signed JSON webhooks. No Sidekiq workers or scraping code required for the monitoring path.
49
+
50
+ Common use cases
51
+ ----------------
52
+ - Website / page change monitoring
53
+ - Competitor price and plan monitoring
54
+ - Package / shipment tracking alerts
55
+ - Stock and availability watches
56
+ - Recurring web scraping with structured findings
57
+ - Change detection webhooks for Rails and API backends
58
+
59
+ Keywords: rails, ruby, sidekiq, activejob, background jobs, webhook, web scraping,
60
+ website monitoring, price monitoring, package tracking, cron, scheduler, llm, agents,
61
+ change detection, faraday.
62
+
63
+ Docs: https://cloud.meerkatagents.com/docs/introduction
41
64
  email:
42
65
  - hello@meerkatagents.com
43
66
  executables: []
@@ -57,16 +80,20 @@ files:
57
80
  - lib/meerkat/railtie.rb
58
81
  - lib/meerkat/resources/api_keys.rb
59
82
  - lib/meerkat/resources/base.rb
83
+ - lib/meerkat/resources/monitors.rb
60
84
  - lib/meerkat/resources/signup.rb
61
85
  - lib/meerkat/resources/tasks.rb
62
86
  - lib/meerkat/version.rb
63
87
  - lib/meerkat/webhooks.rb
64
- homepage: https://github.com/Tiny-Bubble-Company/meerkat-ruby
88
+ homepage: https://cloud.meerkatagents.com/docs/introduction
65
89
  licenses:
66
90
  - MIT
67
91
  metadata:
92
+ homepage_uri: https://cloud.meerkatagents.com/docs/introduction
93
+ documentation_uri: https://cloud.meerkatagents.com/docs/introduction
68
94
  source_code_uri: https://github.com/Tiny-Bubble-Company/meerkat-ruby
69
95
  changelog_uri: https://github.com/Tiny-Bubble-Company/meerkat-ruby/blob/main/CHANGELOG.md
96
+ bug_tracker_uri: https://github.com/Tiny-Bubble-Company/meerkat-ruby/issues
70
97
  rubygems_mfa_required: 'true'
71
98
  post_install_message:
72
99
  rdoc_options: []
@@ -86,6 +113,6 @@ requirements: []
86
113
  rubygems_version: 3.4.1
87
114
  signing_key:
88
115
  specification_version: 4
89
- summary: Async agent task APImonitor websites for changes, track deliveries, watch
90
- prices/stock via webhooks.
116
+ summary: Change Intelligence for Railswebsite monitoring, price tracking, webhooks
117
+ (not Sidekiq).
91
118
  test_files: []