Scheduled watch

A check only helps when someone runs it. The scheduled watch runs the CLI every 4 hours in your CI and opens an issue when a heads-up, an alert or a security release is new for your stack. Quiet runs cost nothing and open nothing.

The profile

The watch reads .stackalarm.yaml at the root of the project. The skill writes it at the end of a /stackalarm run when you accept the watch, and refreshes it on later runs.

.stackalarm.yaml
# Written by the stackalarm skill, refreshed on each /stackalarm run.
tags: [php, symfony, composer, gitlab, docker]
keywords: [frankenphp]
packages: [symfony/http-kernel, twig/twig]
stack:
  - {name: php, version: "8.3", precision: branch, from: Dockerfile}
  - {name: gitlab, version: unknown, precision: unknown, from: git remote}
FieldUse
tagsTechnologies to watch, as in --tag.
keywordsWords searched in the general sources, as in --keyword.
packagesPackage names from the lockfile, as in --package.
stackWhat the skill found, with the version, its precision (exact, branch, range, unknown) and the file it came from. Shown in reports, never used to filter.

The file is committed and may be public: it never holds host names, internal URLs, IP addresses or secrets (gitlab, not gitlab.acme.internal). Check it with stackalarm news --profile .stackalarm.yaml --since 24h.

GitHub Actions

Copy ci/github/stackalarm.yml to .github/workflows/:

.github/workflows/stackalarm.yml
name: stackalarm

on:
  schedule:
    - cron: "17 */4 * * *"
  workflow_dispatch:

permissions:
  contents: read

jobs:
  watch:
    runs-on: ubuntu-latest
    permissions:
      contents: read
      issues: write
    steps:
      - uses: actions/checkout@v7
        with:
          persist-credentials: false
      - uses: yoanbernabeu/stackalarm@v0.6.0
        with:
          anthropic-api-key: ${{ secrets.ANTHROPIC_API_KEY }}
          nvd-api-key: ${{ secrets.NVD_API_KEY }}

No token to create: the workflow's automatic github.token opens the issue and lifts the GitHub API cap. The optional secrets are ANTHROPIC_API_KEY (the triage, below) and NVD_API_KEY.

The workflow uses the yoanbernabeu/stackalarm action, which you can also call from your own workflows. Its inputs and outputs, as declared in action.yml:

InputDefaultDescription
profile.stackalarm.yamlThe project profile written by the stackalarm skill.
since48hHow far back to look. Longer than the schedule interval, so a delayed run misses nothing; the state removes the duplicates.
fail-onheads-up,alert,releaseThe stages that wake the watch up (heads-up, alert, release, advisory, news).
anthropic-api-keyemptyOptional. With it, Claude runs the stackalarm skill on the new items, and an issue is opened only when the project is concerned. Without it, every new item opens an issue.
issuetrueOpen an issue ("true" or "false").
labelstackalarmThe label of the issues, created if missing.
installtrueInstall stackalarm ("true"), or use the one already on the PATH ("false").
versionemptyThe stackalarm version to install (v0.5.0). Empty means the version of this action when it is pinned to a release, the latest release otherwise.
github-token${{ github.token }}Token used to open the issue and to raise the GitHub API rate limit of the CLI.
nvd-api-keyemptyOptional NVD API key, to search the NVD faster.
OutputDescription
found"true" when new items with one of the fail-on stages were found.
decisionWhat decided the issue: act, prepare or none (from the triage), exploited (an exploited vulnerability overrode "none"), untriaged (no key, or the triage failed). Empty when nothing was found.
reportPath of the Markdown report.
issue-urlURL of the issue opened, if any.

Triage by Claude

Raw news is not a verdict: a Go release the project already runs is news, not a reason to act. With the ANTHROPIC_API_KEY secret, when the CLI finds something new, Claude runs the skill in triage mode and the issue depends on its decision. Claude is called only on the runs that find something new.

The run findsWhat happens
Nothing newNothing is opened. Claude is not called.
New items, decision actAn issue "stackalarm: act now", verdict first, the raw news folded below.
New items, decision prepareAn issue "stackalarm: prepare", same layout.
New items, decision noneNo issue. The verdict stays in the run summary.
Decision none, but the report holds an item from CISA KEV or the EUVD exploited listAn issue anyway: a vulnerability exploited in the wild that names a watched technology always reaches a person.
New items, the triage failsAn issue with the raw news, saying the triage did not complete.
New items, no API keyAn issue with the raw news. Judge it with /stackalarm triage <issue link> in your agent.

Claude reads text written by others, so it runs locked down. It cannot open issues, push or change the project's files: it can only write its verdict and its decision, and the action opens the issue from them. The tools it is allowed, read from action.yml:

GitLab CI

Include the job in .gitlab-ci.yml:

.gitlab-ci.yml
include:
  - remote: https://raw.githubusercontent.com/yoanbernabeu/stackalarm/main/ci/gitlab/stackalarm.yml

Then two steps only you can do:

  1. Add a masked CI/CD variable STACKALARM_GITLAB_TOKEN: a project access token with the api scope and the Reporter role, to open the issues.
  2. Create a pipeline schedule (Build > Pipeline schedules), every 4 hours: 17 */4 * * *. The job runs only on schedules.

Two optional variables, read by the CLI as on your machine:

VariableWhy
GITHUB_TOKEN Recommended on shared runners. The GitHub advisory sources allow 60 anonymous requests per hour per IP, and shared runners share their IP with many other jobs: without a token, those sources often fail. Use a GitHub token with no permission at all (a fine-grained token with public repositories, read-only), masked.
NVD_API_KEYFaster NVD searches. Free.

The job's variables, which you can override:

VariableDefault
STACKALARM_PROFILE.stackalarm.yaml
STACKALARM_SINCE48h
STACKALARM_FAIL_ONheads-up,alert,release
STACKALARM_LABELstackalarm

GitLab has no triage by Claude: every new heads-up, alert or security release opens an issue with the raw news, to judge with /stackalarm triage <issue link>. Without the token, the job fails instead of staying silent.

Each item reported once

The CI cache keeps a state file of the items already handled. It is saved only once the run has dealt with them (issue opened, or none needed): if the issue cannot be opened, the next run reports the items again. An item may be reported twice, never missed. On GitLab runners without a shared cache, a few items may be reported twice.

The watch looks back 48 hours by default, longer than the 4-hour schedule, so a delayed or failed run misses nothing; the state removes the duplicates.

Next: Sources