Skip to main content

One-line, fail-open wrapper for LLM calls — silent-breakage detection for indie AI apps.

Project description

chirppal (Python)

One-line, fail-open wrapper for LLM calls — a smoke alarm for the AI features in your app. Wrap a call and ChirpPal watches it for silent breakage (refusals, malformed JSON, empty output, latency spikes) and fire-and-forget reports metadata only to the ChirpPal backend. It never changes what your call returns, raises, or how long it takes.

  • Fail-open — any error inside the wrapper (a check bug, a network blip) is swallowed. track()'s return value, exception, and effective timing always match calling your function directly.
  • Privacy-first — by default only metadata leaves your process (pass/fail, latency, model, which check failed). Prompt/response content is sent only if you explicitly opt into semantic-judge sampling.
  • Zero dependencies — standard library only.

Install

pip install chirppal

Quickstart

project= is the one thing you always pass — it selects that project's checks, default model, sampling rate, and API key from chirppal.config.json (see below). Create the config first, then wrap the call:

{
  "config_version": 2,
  "projects": {
    "prod-support-bot": {
      "key_env": "CHIRPPAL_KEY_SUPPORT",
      "checks": { "no_error": true, "not_empty": true }
    }
  }
}
CHIRPPAL_KEY_SUPPORT=cp_live_...     # this project's key, from the dashboard
from chirppal import track

resp = track(
    lambda: client.responses.create(model="gpt-4.1", input=prompt),
    model="gpt-4.1",              # pass the exact model id so deprecation radar can flag it
    project="prod-support-bot",
)

track() returns exactly what the wrapped call returns (and re-raises its exceptions unchanged). No config file at all? track() still works — it just monitors nothing and reports under a dev-only fallback key, exactly like before you had a config.

# Optional: override the endpoint. Defaults to https://api.chirppal.com/api/ingest.
# For local development against your own backend:
CHIRPPAL_ENDPOINT=http://localhost:8000/api/ingest

Config: one project = one policy

A chirppal.config.json at your repo root declares one or more projects — each is a full policy: which checks to run, which environment variable holds its key (key_env), an optional default model, and an optional sampling_rate for passing calls (failures always send regardless). Full format spec, shared with the JS/TS client: CONFIG.md.

{
  "config_version": 2,
  "projects": {
    "support-bot": {
      "key_env": "CHIRPPAL_KEY_SUPPORT",
      "model": "gpt-4.1",
      "sampling_rate": 0.25,
      "checks": {
        "max_latency_ms": 3000,
        "no_refusal": true,
        "valid_json": { "required_keys": ["status"] }
      }
    },
    "billing-bot": {
      "key_env": "CHIRPPAL_KEY_BILLING",
      "checks": { "no_error": true, "must_contain": ["invoice"] }
    }
  }
}
# reads checks + model + sampling_rate + key from the "support-bot" entry above
track(lambda: call_llm(), project="support-bot")

Running two projects (each with its own key) from the same process just means using each project's name in its own track() calls — no extra setup:

track(lambda: call_support_bot(), project="support-bot")
track(lambda: call_billing_bot(), project="billing-bot")

A code-level checks=[...] list still works as an escape hatch — it replaces just the checks for that call; key_env/model/sampling_rate from the named project still apply:

from chirppal import track, checks

track(
    lambda: call_llm(),
    checks=[checks.valid_json(required_keys=["status"]), checks.no_refusal()],
    project="support-bot",
)

model=/sampling_rate= passed to track() likewise override that project's JSON defaults for a single call (e.g. a dynamically-chosen model).

Reading the config is itself fail-open: a missing or broken config, an unset key_env variable, or an unknown project name all warn once and fall back to monitoring less (never checks, or a dev-only fallback key) — never breaks track().

Matching an event back to your own system

Pass metadata= to tag an event with your own identifiers (e.g. a user or request id), and check the dashboard's per-event detail against your own logs:

track(
    lambda: call_llm(),
    project="support-bot",
    metadata={"user_id": "u_123", "api_call_id": req.id},
)

You can also set a static default per project in chirppal.config.json ("metadata": {"env": "production"}) — a per-call value merges with it and wins on a shared key. Bounded to 10 keys / string or number values / 200-char strings; anything past that is dropped or truncated (never an error) and surfaces on the dashboard's Integration health panel. Not encrypted — never put API keys, passwords, or personal data in it.

Every failed check also reports a safe-subset detail (e.g. which keyword was missing, or that JSON parsing failed at a given line/column) — visible on the dashboard's event list — and every event carries a small Integration health snapshot (is the response shape recognized, was anything clamped or truncated, what config is actually in effect) that the dashboard's project page shows as green/yellow. See CONFIG.md and CONTRACT.md §6 for the full details.

Privacy

The default payload is metadata only — no conversation content. prompt and output are sent only on a call you opted into judge-sampling for (judge_sampling_rate > 0, a Pro feature). No other path ever sends your users' prompts or your model's output. metadata is a separate, unrelated opt-in (see above) that's sent on every event once you set it — it's not encrypted, so treat it like a log line, not a vault.

Publishing (maintainers)

Requires a PyPI account + API token — this step is done by hand, not by CI:

cd sdk/chirppal
python -m build            # produces dist/*.whl and dist/*.tar.gz
python -m twine upload dist/*

License

MIT — see LICENSE.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

chirppal-0.1.0.tar.gz (17.7 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

chirppal-0.1.0-py3-none-any.whl (20.6 kB view details)

Uploaded Python 3

File details

Details for the file chirppal-0.1.0.tar.gz.

File metadata

  • Download URL: chirppal-0.1.0.tar.gz
  • Upload date:
  • Size: 17.7 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.11.9

File hashes

Hashes for chirppal-0.1.0.tar.gz
Algorithm Hash digest
SHA256 a4948bafdba5f6a75b5527ed095a23d875fef7a3074d6e7088c8cf9e3d1286b6
MD5 8902a658c02ad393e18ccb4492949aa2
BLAKE2b-256 123d4ba08abdf5c3146285ce11d605a03aafbfa86e48f3b31c95d61c3616b41f

See more details on using hashes here.

File details

Details for the file chirppal-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: chirppal-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 20.6 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.11.9

File hashes

Hashes for chirppal-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 eaa06d9991b8e66465e3d675a230f703bbc586f0c0d2fbd23bc21d56e603c48f
MD5 a5b9523e0950af0293e944e7f25d61b4
BLAKE2b-256 a8703c1efe900260a2075703916d2e96efeb7600e24aa4fb7b313fc37dffe6e0

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page