Monitors-as-code.
Past a certain team size — roughly four engineers — click-to-create monitors stops scaling. Monitors-as-code puts every monitor in source control so you can diff changes on pull requests, roll back regressions, and bootstrap new environments with a single command.
Install the CLI
# via npm
npm install -g @brily/cli
# via homebrew
brew install brily/tap/cli
# verify
brily --version
brily auth login # opens a browser; pastes token locallyThe manifest
Every monitor lives as a file under .brily/monitors/. YAML is the default; JSON works if you prefer. A minimum monitor:
# .brily/monitors/homepage.yml
kind: Monitor
name: homepage
url: https://example.com
method: GET
interval_seconds: 60
regions: [fra, hel, ams]
quorum: 2
assertions:
- type: status
operator: eq
value: 200
- type: body_contains
value: Sign in
alert_policy:
severity: p1
slack_channel: "#ops-alerts"
escalate_after_minutes: 10Deploy from CLI
# preview what would change (read-only)
brily plan
# apply the diff
brily apply
# apply only specific monitors
brily apply --filter homepagebrily planis safe to run on any branch. It prints a unified-diff style comparison between your local manifests and what's live in the project.
Deploy from CI
Wire brily apply into your main-branch CI. Example for GitHub Actions:
name: Deploy monitors
on:
push:
branches: [main]
paths: [.brily/**]
jobs:
apply:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: brily/setup-cli@v1
- run: brily apply
env:
BRILY_TOKEN: ${{ secrets.BRILY_TOKEN }}Plan on pull requests
Add a PR-only workflow that runs brily plan and posts the output as a PR comment. Reviewers can see exactly what will change before approval.
- name: Plan monitors
run: brily plan --format=markdown > plan.md
env:
BRILY_TOKEN: ${{ secrets.BRILY_TOKEN_READONLY }}
- uses: marocchino/sticky-pull-request-comment@v2
with:
header: brily-plan
path: plan.mdOwnership and sharding
Put each domain's monitors in its own subdirectory and use CODEOWNERS to enforce review:
# .github/CODEOWNERS
.brily/monitors/checkout/ @acme/checkout-team
.brily/monitors/billing/ @acme/billing-team
.brily/monitors/web/ @acme/web-teamMixing code and UI
You can manage some monitors in code and others in the UI — but we don't recommend it. The CLI has a --prune flag that deletes monitors not present in manifests, which will wipe UI-created monitors if enabled. Either go all-in on code (recommended) or keep them in the UI entirely.
Templating and composition
YAML anchors cover the 80% case. For anything more complex, we support Go templates:
{{- range .environments }}
---
kind: Monitor
name: api-health-{{ .name }}
url: {{ .api_base }}/health
interval_seconds: 60
regions: {{ .regions | toYaml | nindent 2 }}
{{- end }}Context variables come from .brily/config.yml or environment variables with a BRILY_VAR_ prefix.
When to adopt this
- Four engineers or more— the "who owns this monitor" problem starts appearing around here.
- Multiple environments — staging and production monitors that share config are a copy-paste nightmare in the UI.
- Compliance sensitivity — audit trails from git history are stronger than UI change logs for SOC 2 / ISO 27001.
If none of these apply, the UI is fine. Adoption can be incremental — export existing monitors to manifests with brily export, then wire up the CI job when you're ready.