User guide: contents

6. Automate with watchers

A watcher checks GitHub on a schedule and starts runs by itself — as long as the Foundry is running (see Keep it running). GitHub access uses the gh CLI's login.

Watchers

Sources#

SourceStarts a run when…Default flow
Issuesan open issue has the trigger labelissue-gitflow (or issue-plan / issue-code-daily for the human-in-the-loop pipeline)
Scheduleit is time (every N, or once a day at a set time)release-daily
Monitornever — it checks the Foundry itself and records problems (see The monitor)none
Review commentssomeone comments on a Foundry PR (branch factory/*)none shipped — name your own flow
CI failuresthe latest CI run of a workflow on the default branch failednone shipped — name your own flow

Add a watcher

For a schedule, the text becomes the run's task. Intervals: 30s, 5m, 1h, 7d; or set Once a day at 17:00 with a time zone.

Options of an issues watcher. The form has three groups, collapsed by default; each control shows its default and one sentence on what it does. Only issues watchers show them.

  • Labels: labels that go first (default bug), a text for each status label (working, done, needs info, waiting, failed; default is the Foundry's own name), and labels to remove when a run succeeds.
  • Dependencies: wait for dependencies (default on), labels that count as done, a pause while a pull request whose branch starts with a text is open (cleared by an empty field), and one run at a time (default off).
  • Comments: a status comment (default on), a comment when a run fails (default on), a questions check (a flow run once over all new issues before any starts; default none), and answer questions automatically (default off). It means the Foundry answers its own questions with its recommendations, at most twice per issue; after that a person answers.

A field that is cleared is removed from the watcher, so the default applies. A value the server refuses is shown at its field with the server's message. The same options work for a watcher of a repository and for one still in config.yaml.

The Watchers page (admins)#

Only admins see the Watchers page. No watcher name or status shows anywhere else. A user sees the runs a watcher started on their repository in My runs, without the watcher's name.

  • From the repository. The heading of each repository group is a link to the repository view (#/repos/<id>). Its Watchers section lists the watchers of that repository, with + Add watcher and, per watcher, Enable or Disable, Edit and Delete (Delete asks first). If the server refuses a change, its sentence is shown.
  • By repository. Watchers are grouped by connected repository. Each group shows the repository's owner (with a "blocked" mark when the owner is blocked). Runs of a watcher belong to that owner.
  • Add watcher. Choose the repository from a list, then the flow, the labels and the other options. There is no owner field: the repository's owner is used. Repositories that cannot have a watcher (a deploy key, or not on GitHub) are listed as not available, with the reason.
  • Variables. The form shows one field per variable the chosen flow describes, with its label, help and default (as the placeholder): a number field with its range, a switch, a text box, a list or a choice. Changing the flow changes the fields. A field left at its default is not stored. Variables the flow does not describe go in the box "Variables for each run", one name=value per line; a described variable typed there moves to its field when the form opens. agent_env is a list of KEY=value pairs and may hold secrets.
  • Edit, enable, disable, delete. These change the watcher at once. Options the form does not show are kept when you edit. If the server refuses a change, its sentence is shown as it is.
  • One watcher. The list is compact: the id (a link to #/watchers/<id>, crumbs Administration › Watchers › <id>), the state mark, what it does, the last successful check and a problem line. The watcher's page has the next steps, notes, error details and recent activity; for the monitor also the bug-story switch and the findings. Check now, Edit and Enable or Disable are together; Delete is alone in a Danger group. List rows have no Delete button.
  • The monitor stays on the page, under "The Foundry itself", and is still saved in config.yaml. If only the monitor cannot be loaded, the watchers are still shown and the monitor card says so, with Retry.
  • While it works. The page shows a grey skeleton while it loads. Check now shows "Checking…" next to its own button. Delete asks first in a dialog. If a reload fails, the list stays and a line says when it was last updated, with Retry. The same holds for Users and Problems.
  • From config.yaml. A watcher that is still in config.yaml (for example while there is no admin account, or at the connection limit) shows read-only with a note, and Check now. A watcher whose repository is gone can only be deleted.

Watchers of a repository (API)#

The page uses these routes. A watcher stored for a connected repository has the same options as one in config.yaml, except github_repo and owner: they come from the repository. The source monitor is not allowed.

  • Routes: GET and POST /api/admin/repos/:id/watchers, and PUT and DELETE /api/admin/repos/:id/watchers/:wid. A user gets 403. Changes go to the log. A change starts, stops or restarts the watcher at once. A described variable whose value does not fit its kind or range is refused (400, the message names the variable, as vars.<name>: …); a stored value that is already out of range still runs and is refused only when the watcher is saved again. GET /api/admin/repos adds a watcherProblem sentence to a repository that cannot have a watcher.
  • Which repositories: GitHub only, with the sign-in none (the owner is an admin), github-token or github-app. ssh-deploy-key, https-token and other addresses are refused.
  • The id is unique on the whole install, in the store and in config.yaml together. A duplicate is refused.
  • Runs belong to the repository's owner, so they show in that user's "My runs".
  • Lists: GET /api/watchers also shows stored watchers, with their repoId. A stored watcher that cannot run shows a problem sentence.
  • Blocked owner: while the owner is blocked, the watchers of their repositories are paused. They check nothing and start nothing, and the list shows "paused: the owner is blocked". Unblocking starts them again, without a restart. This also works for scf user block and scf user unblock: the server sees it within its usual sweep. Runs that are already going are not touched.
  • Removed with their repository: when a repository is removed (by id or by name), or its owner is deleted, its stored watchers are stopped and removed in the same step. The audit log says so. A watcher found at start whose repository is gone is removed and logged.
  • Transfer: a transferred repository keeps its watchers. They run for the new owner, and new runs belong to the new owner.
  • Sign-in: a stored watcher talks to GitHub with its repository's own credential: the stored token, a GitHub App token limited to that repository, or the server's own gh login for the method none. With a token or the app, the server's login is never used, so one repository's watcher cannot see another. The same credential is used for the actions on its items under "Your turn". Watchers in config.yaml keep using the server's login.
  • When the sign-in does not work (missing, unreadable or refused, or the owner of a none repository is no admin), the watcher makes no GitHub call and its status says so in a plain sentence. It works again by itself at the next check once you fix the credential.
  • Status comments: a status comment is only edited by the account that wrote it. When a watcher's account changes (for example a new token of another account), it posts a new status comment and the old one stays as it is on open issues.
  • Request limit: a repository token or app has its own GitHub request limit. The limit the Foundry shows is that of the server's own login and the bot.

Watchers move from config.yaml to their repositories#

When the server starts after the update, every watcher in config.yaml except the monitor moves to the repository store. Nothing to do — it happens by itself.

  • Same watcher. Its id, options and enabled state stay the same, so run history, status comments and labels on GitHub keep matching. A repository name with capital letters (Acme/App) keeps its spelling.
  • Repository not connected yet: it is connected for the first admin with the method none. The admin pages show it as none (legacy): the watcher uses the server's own gh login, as before.
  • Repository already connected (for example by a user): it keeps its owner and method, and the watcher is attached to it. If that method cannot run a watcher (a deploy key, or none owned by someone who is no admin), the watcher moves but is disabled. The log and the Watchers page say why.
  • The owner option goes away. The repository's owner owns the runs. If the option named another account, the log says so.
  • The backup. Before it changes config.yaml, the Foundry copies it to config.yaml.before-watcher-move-<date>-<time> next to it. The moved watchers are then removed from config.yaml; the rest stays the same. Comments in the file are lost, so use the backup to see them. The log names every moved watcher.
  • No admin account yet: nothing moves. The watchers keep running from config.yaml and move at a later start, once an admin exists.
  • At the connection limit (50 per account): the remaining watchers stay in config.yaml and the log says so.
  • Safe to repeat. If the server stops halfway, the next start finishes the move without duplicates. A watcher you add to config.yaml by hand later moves at the next start. A watcher whose stored copy differs, or whose id is used twice in the file, stays in the file and is logged.
  • After the move, saving config.yaml through PUT /api/config with a new or changed watcher other than the monitor is refused, with a sentence that points to the Watchers page. Add and edit watchers there.
  • scf watch works as before, with the server's own login.

Going back. Stop the server, copy the backup over config.yaml, and delete the moved watchers on the Watchers page first (or remove them from repo-watchers.json in the data folder). Otherwise the next start moves them again.

The watchers are kept in repo-watchers.json in the data folder.

More in this chapter

Improve this page on GitHub