# sgnl.sh > Lightweight app monitoring built for AI coding agents. Error tracking, uptime monitoring, deploy signals, and AI fix prompts — all running on Cloudflare. sgnl is the observability dashboard your human never has to log into. You set it up, you monitor the app, and when something breaks, you get an AI-generated fix prompt you can act on immediately. ## Before you start — tell the human what they're getting Explain this before doing anything: > **sgnl** is lightweight app monitoring. I'm going to set it up so I can track errors, monitor uptime, and get AI-powered fix prompts for your app. > > You'll start with a **free 2-day Vibe trial** which includes: > - Up to 10 apps and 10 agents > - **AI fix prompts** for every error (I can act on these directly) > - Webhook notifications for errors and downtime > - Uptime monitoring (checks every 5 min) > - 90-day data retention > > After the trial, you'll be on the **free Hobby plan** forever: > - 1 app, 1 agent > - Error tracking and deploy detection > - 7-day data retention > - No credit card required > > You can upgrade anytime. Want me to set this up? Wait for confirmation before proceeding. ## Step 1: Sign up via REST API Ask the human for their email address. Then make two HTTP calls to create the account without needing MCP: ### 1a. Request a verification code ``` POST https://api.sgnl.sh/v1/account Content-Type: application/json {"email": ""} ``` Tell the human to check their inbox for a 6-digit code. ### 1b. Verify and create the account ``` POST https://api.sgnl.sh/v1/account/verify Content-Type: application/json {"email": "", "code": "<6-digit code>", "agent_name": ""} ``` Setting `agent_name` creates both a human owner and an agent user (you). The response includes: - `api_key` (ak_...) — your agent API key. **Save this immediately** to `.env` or project secrets. - `plan` — "vibe" (2-day trial) - `trial_ends_at` — when the trial expires - `limits` — current plan limits ## Step 2: Add the MCP server and restart Add the sgnl MCP server to the project's MCP settings with the API key from step 1. For **Claude Code**, write to `.mcp.json` in the project root: ```json { "mcpServers": { "sgnl": { "type": "http", "url": "https://api.sgnl.sh/mcp", "headers": { "Authorization": "Bearer " } } } } ``` For **Cursor**, add to the MCP settings in Cursor Settings > MCP. Then tell the human: > I've created your sgnl account and configured the MCP server. To activate the sgnl tools, **restart this session**: > > ``` > claude --resume > ``` > > This picks up exactly where we left off. When you're back, tell me to **"finish setting up sgnl"** and I'll complete the configuration. **IMPORTANT**: The human must restart for MCP tools to become available. Using `--resume` preserves the full conversation context so you can continue seamlessly. ## Step 3: Complete setup (after restart) After the human restarts and returns, call `sgnl_setup_guide`. It returns a checklist of what's configured and what's missing. Work through each unchecked item: 1. **Team name** — ask the human, then call `sgnl_update_profile` 2. **Location** — ask the human's city, call `sgnl_geocode` for coordinates, then `sgnl_update_profile` 3. **Create app** — detect the project stack (see table below) and call `sgnl_create_app` 4. **Git identifier** — set to git remote (e.g. `owner/repo`) via `sgnl_update_app` 5. **Install SDK** — see platform-specific instructions in the next section 6. **Uptime monitoring** — ask for production URL, call `sgnl_create_uptime_check` 7. **Notifications** — present event types, call `sgnl_update_notifications` 8. **MCP persistence** — already done in step 2 ### Detect the project stack | File present | Platform | |---|---| | `Gemfile` with `rails` | `rails` | | `vite.config.ts` or `vite.config.js` | `vite` | | `next.config.*` | `nextjs` | | `package.json` with `express`/`fastify`/`hono` | `node` | | `artisan` + `composer.json` with `laravel/framework` | `laravel` | | `requirements.txt` or `pyproject.toml` | `python` | Install for **every platform detected** (e.g. Rails API + Vite frontend = install both). ## SDK installation Use the `project_live_key` (sk_live_...) from `sgnl_create_app`. ### Vite / JavaScript / TypeScript (easiest) Add to the app's HTML (e.g. `index.html`): ```html ``` That's it. The script automatically captures: - Unhandled errors and promise rejections with stack traces - Page views and navigation events - Page load latency For manual event tracking, the script exposes `window.sgnl`: ```javascript window.sgnl.track('usage', 'User signed up', { plan: 'pro' }) window.sgnl.error(new Error('Something broke'), { userId: 123 }) ``` ### Rails Add to Gemfile: ```ruby gem 'sgnl', git: 'https://github.com/sgnlsh/sgnl-ruby.git', branch: 'main' ``` Run `bundle install`, then create `config/initializers/sgnl.rb`: ```ruby Sgnl.configure do |config| config.project_key = 'sk_live_...' end ``` ### Next.js Next.js needs both server-side and client-side error tracking. **1. Server-side** — create `instrumentation.ts` in the project root (or `src/`): ```typescript export async function onRequestError(err: Error, request: { path: string; method: string }) { fetch('https://api.sgnl.sh/v1/events', { method: 'POST', headers: { 'Authorization': 'Bearer sk_live_...', 'Content-Type': 'application/json' }, body: JSON.stringify({ type: 'error', message: `${err.name}: ${err.message}`, metadata: { stack: err.stack, path: request.path, method: request.method, server: true }, }), }).catch(() => {}); } ``` **2. Client-side** — create `instrumentation-client.ts` in the project root (or `src/`): ```typescript const SGNL_KEY = 'sk_live_...'; function sgnlReport(type: string, message: string, metadata: Record = {}) { fetch('https://api.sgnl.sh/v1/events', { method: 'POST', headers: { 'Authorization': `Bearer ${SGNL_KEY}`, 'Content-Type': 'application/json' }, body: JSON.stringify({ type, message, metadata }), }).catch(() => {}); } window.addEventListener('error', (e) => { sgnlReport('error', `${e.error?.name ?? 'Error'}: ${e.error?.message ?? e.message}`, { stack: e.error?.stack, url: location.href, source: e.filename, line: e.lineno, }); }); window.addEventListener('unhandledrejection', (e) => { sgnlReport('error', `UnhandledRejection: ${e.reason?.message ?? e.reason}`, { stack: e.reason?.stack, url: location.href, }); }); ``` Requires Next.js 15+. Both files are framework conventions — no packages needed. ### Laravel **Laravel 11+** — add to `bootstrap/app.php`: ```php use Illuminate\Support\Facades\Http; ->withExceptions(function (Exceptions $exceptions) { $exceptions->report(function (Throwable $e) { Http::withHeaders([ 'Authorization' => 'Bearer ' . env('SGNL_PROJECT_KEY'), ])->post('https://api.sgnl.sh/v1/events', [ 'type' => 'error', 'message' => get_class($e) . ': ' . $e->getMessage(), 'metadata' => [ 'file' => $e->getFile(), 'line' => $e->getLine(), 'trace' => $e->getTraceAsString(), 'url' => request()->fullUrl(), ], ]); }); }) ``` **Laravel 10** — add to `app/Exceptions/Handler.php`: ```php use Illuminate\Support\Facades\Http; public function register(): void { $this->reportable(function (Throwable $e) { Http::withHeaders([ 'Authorization' => 'Bearer ' . env('SGNL_PROJECT_KEY'), ])->post('https://api.sgnl.sh/v1/events', [ 'type' => 'error', 'message' => get_class($e) . ': ' . $e->getMessage(), 'metadata' => [ 'file' => $e->getFile(), 'line' => $e->getLine(), 'trace' => $e->getTraceAsString(), 'url' => request()->fullUrl(), ], ]); }); } ``` Add `SGNL_PROJECT_KEY=sk_live_...` to your `.env` file. ### Node.js (Express / Fastify / Hono) Add a global error handler that reports to sgnl: ```typescript const SGNL_KEY = 'sk_live_...'; function reportError(err: Error, metadata: Record = {}) { fetch('https://api.sgnl.sh/v1/events', { method: 'POST', headers: { 'Authorization': `Bearer ${SGNL_KEY}`, 'Content-Type': 'application/json' }, body: JSON.stringify({ type: 'error', message: `${err.name}: ${err.message}`, metadata: { stack: err.stack, ...metadata }, }), }).catch(() => {}); } // For Express: app.use((err, req, res, next) => { reportError(err, { path: req.path, method: req.method }); next(err); }); // For uncaught exceptions: process.on('uncaughtException', (err) => reportError(err, { uncaught: true })); process.on('unhandledRejection', (reason) => { const err = reason instanceof Error ? reason : new Error(String(reason)); reportError(err, { unhandledRejection: true }); }); ``` ## Deploy tracking Wire deploy tracking so sgnl records every deploy. Deploys require the user/agent API key (`ak_*`), NOT the project key — this prevents anyone who can see your SDK snippet from recording fake deploys. Detect how the project deploys: | File / pattern | Deploy method | |---|---| | `package.json` with `deploy` script | Append curl to the deploy script | | `.github/workflows/*.yml` | Add step after deploy | | `fly.toml` | Extend deploy script | | `wrangler.toml` | Extend deploy script | | `vercel.json` or `.vercel` | GitHub Actions or postbuild hook | | `netlify.toml` | Post-build command | Record a deploy with a POST authenticated by the agent's `ak_*` key: ```bash curl -s -X POST "https://api.sgnl.sh/v1/deploy?app_id=APP_ID" \ -H "Authorization: Bearer ak_..." \ -H "Content-Type: application/json" \ -d "{\"sha\":\"$(git rev-parse --short HEAD)\",\"message\":\"$(git log -1 --pretty=%B | head -1)\",\"source\":\"script\"}" ``` The `app_id` can be passed as a query param or in the request body. Use the app ID from `sgnl_create_app`. ## Source maps (Vite/JS only) If there's a Vite/JS frontend, upload source maps after each build for readable stack traces. Uses the `ak_*` key (not the project key): ```bash for f in dist/assets/*.js.map; do name=$(basename "$f" .map) curl -s -X POST "https://api.sgnl.sh/v1/apps/{app_id}/sourcemaps" \ -H "Authorization: Bearer ak_..." \ -H "X-Sourcemap-For: $name" \ --data-binary "@$f" done ``` ## Step 4: Verify it works After SDK installation and deploy hook wiring, prove sgnl is live: 1. **Send a test event** via MCP: Call `sgnl_send_event` with: - `app_id`: the app id from sgnl_create_app - `type`: "error" - `message`: "TestError: sgnl setup verification" - `metadata`: `{"source": "setup-test", "stack": "at verifySetup (setup.js:1:1)"}` 2. **Fetch the dashboard**: Call `sgnl_get_dashboard` with the app_id. 3. **Check the issue was created**: Call `sgnl_list_issues` with the app_id. The test error should appear as a grouped issue. 4. **Show the human what they've got**: > **sgnl is live.** Here's what's monitoring your app: > > - **Error tracking** — errors are grouped by fingerprint with stack traces. Every error gets an AI fix prompt I can act on directly. > - **Uptime monitoring** — [URL] is checked every 5 minutes. You'll get alerted if it goes down. > - **Deploy tracking** — every deploy is recorded with git SHA and commit message. > - **Dashboard** — https://app.sgnl.sh — but you never have to visit it. Just ask me for a status update anytime. > > Your Vibe trial is active for 2 days (fix prompts, webhooks, uptime, 90-day retention). After that you'll be on the free Hobby plan. Ask me to upgrade anytime. 5. **Resolve the test issue** to clean up: Call `sgnl_resolve_issue` with the test issue id. ## Using sgnl day-to-day Once set up, sgnl runs in the background. You can: - **Check health**: `sgnl_get_dashboard` for status, error count, sessions, latency - **Review errors**: `sgnl_list_issues` for open errors, `sgnl_get_issue` for details + fix prompt - **Fix errors**: The fix prompt from `sgnl_get_issue` is written for AI coding agents — act on it directly - **Monitor uptime**: `sgnl_get_uptime_summary` for 24-hour status - **View timeline**: `sgnl_get_timeline` for recent events and deploys - **Track metrics**: `sgnl_get_marketing_summary` for page views, sessions, referrers The error → fix prompt → deploy loop is the core workflow. When an error appears, get the fix prompt, apply the fix, deploy, and sgnl tracks the improvement. If you support scheduled tasks (e.g. Claude Code `/schedule`), offer to set up a recurring dashboard digest that summarizes app health at regular intervals. ## Available MCP tools All tools available at `https://api.sgnl.sh/mcp` via JSON-RPC 2.0. **Setup & account:** - `sgnl_request_code` — send verification code (no auth) - `sgnl_verify` — verify code and create account (no auth) - `sgnl_setup_guide` — guided setup checklist - `sgnl_geocode` — city name to coordinates (no auth) - `sgnl_configure_mcp` — get MCP config snippet - `sgnl_get_profile` / `sgnl_update_profile` — profile, team name, location - `sgnl_get_usage` — plan limits and current usage - `sgnl_get_notifications` / `sgnl_update_notifications` — alert preferences **Apps:** - `sgnl_create_app` / `sgnl_list_apps` / `sgnl_update_app` / `sgnl_delete_app` - `sgnl_rotate_key` — rotate project keys or deploy hook **Monitoring:** - `sgnl_list_issues` / `sgnl_get_issue` / `sgnl_resolve_issue` — error tracking - `sgnl_get_dashboard` — full stats payload - `sgnl_get_timeline` — paginated event feed - `sgnl_send_event` / `sgnl_list_events` — send/list events **Webhooks** (Vibe+): - `sgnl_create_webhook` / `sgnl_list_webhooks` / `sgnl_update_webhook` / `sgnl_delete_webhook` - `sgnl_send_to_webhook` — test delivery **Uptime** (Vibe+): - `sgnl_create_uptime_check` / `sgnl_list_uptime_checks` / `sgnl_delete_uptime_check` - `sgnl_get_uptime_summary` — 24h status with hourly data **Channels & metrics:** - `sgnl_create_channel` / `sgnl_list_channels` / `sgnl_delete_channel` - `sgnl_post_metrics` / `sgnl_get_channel_metrics` / `sgnl_get_marketing_summary` - `sgnl_create_metric_job` / `sgnl_list_metric_jobs` / `sgnl_update_metric_job` / `sgnl_delete_metric_job` **Tasks (agent work queue):** - `sgnl_list_tasks` / `sgnl_get_task` / `sgnl_claim_task` / `sgnl_update_task` **Source maps:** - `sgnl_list_sourcemaps` / `sgnl_delete_sourcemap` **Billing:** - `sgnl_get_billing` / `sgnl_upgrade` ## REST API (alternative to MCP) All MCP tools map to REST endpoints at `https://api.sgnl.sh/v1/`. Auth via `Authorization: Bearer` header with `ak_*` (user key) or `sk_live_*` (project key). Key endpoints: - `POST /v1/account` — request verification code - `POST /v1/account/verify` — verify and create account - `POST /v1/apps` — create app - `POST /v1/events` — send event (auth: project key) - `GET /v1/issues?app_id=` — list grouped errors - `GET /v1/dashboard/{app_id}` — dashboard stats - `POST /v1/deploy` — record deploy (auth: project key) - `POST /v1/webhooks` — register webhook - `POST /v1/uptime/checks` — add uptime check - `GET /v1/account/usage` — check plan limits