Thanks for helping. ARGUS is a small tool with two kinds of users, and what you should do depends on which one you are today.
ARGUS is a fork-per-person template. You run your own copy, pointed at your own field. That makes one thing easy to get wrong:
Issues you open in your own fork go to your own tracker, where nobody will see them. Report problems on the upstream repository — Power-Lab/argus — not on your fork.
If the top of the page says "forked from …", you're on your own copy. Click through to the parent and file it there.
| Change | Where |
|---|---|
config.yaml thresholds, tags, recipient |
Your fork only. These are yours. |
registry/sources.yaml queries, journals, feeds |
Your fork only. |
prompts/research.md profile and rubric |
Your fork only. |
| A collector is broken, or a feed 403s for everyone | Upstream issue |
| A bug in scoring, rendering, the digest, or a workflow | Upstream issue or PR |
| A new provider, collector, or feature | Upstream — open an issue first |
The rule of thumb: if the change describes your research, keep it in your fork. If it changes how ARGUS works, bring it upstream.
Keeping your fork current — add the upstream as a remote once, then pull in changes whenever you like:
git remote add upstream https://github.com/Power-Lab/argus.git
git fetch upstream && git merge upstream/mainconfig.yaml, registry/sources.yaml, and prompts/research.md are the files
most likely to conflict, since those are exactly the ones you've made yours.
Keep your versions.
You don't have to notice a broken sweep. If the pipeline fails, the alert
workflow opens an issue automatically with a link to the failed run and a
checklist. It keeps one issue open — repeat failures become comments — and
closes it on its own when a sweep next succeeds.
So an issue labelled pipeline-failure that you didn't file is ARGUS telling
you something. Most of the time it's GitHub infrastructure (The job was not acquired by Runner of type hosted), which clears by itself; the issue will
close after the next good run.
To route those to a person, set the repository variable ALERT_ASSIGNEE to a
GitHub username under Settings → Secrets and variables → Actions →
Variables. Without it the workflow assigns the repository owner, which works
for a personal fork but not for an org-owned repo.
Open an issue on the upstream repo. The templates will ask for what's needed; the two things that make a report immediately actionable are:
1. The scoring line from the run. Every run prints which scorer it actually used and why. It is the single most useful line in the log:
scoring: keyword — groq needs $GROQ_API_KEY — falling back to keyword scoring
2. Which source, if a source is the problem. The dashboard footer shows a
warning when a source has failed three times running. make dry-run prints
per-source counts without writing anything, which is usually enough to pin it
down:
=== DRY RUN — per-source counts (no writes) ===
[ok ] openalex: 41 items
[FAIL] rss:carbonbrief: HTTPError: 403 Client Error
Never paste an API key, a .bib export, or the contents of your library.
- Open an issue first for anything beyond a small fix, so we don't both build the same thing differently.
- Fork, then branch:
git checkout -b fix/short-description - Make the change. Match the surrounding style — the codebase favours short modules, comments that explain why rather than what, and graceful degradation over hard failure.
- Add or update a test.
tests/test_argus.pyruns fully offline: no network, no API keys. Anything that talks to a provider or a feed gets stubbed. If your change fixes a bug, the test should fail without your fix.- Dates in fixtures must be relative (
days_ago(2)), never absolute. Hardcoded dates fall outside the render window as time passes and silently rot the suite — this has already happened once.
- Dates in fixtures must be relative (
- Run
make testlocally. - Push and open the PR. CI runs the suite on Python 3.11–3.13, checks that
registry/sources.yamltags line up withconfig.yaml, and verifies the pipeline still runs with no secrets present.
Small, focused PRs get reviewed faster than large ones. If a change is going to be big, say so in the issue first.
- Does it still work with no API key? Every capability degrades: no key means keyword scoring, no SMTP means no digest. Don't add a hard dependency on a secret.
- Does a failure stay contained? One dead feed logs and is skipped; it never kills a run. New collectors and providers should behave the same way.
- Is a new dependency really necessary?
requirements.txtis deliberately five lines. The OpenAI-compatible provider adapter is written againstrequestsspecifically to avoid adding an SDK per vendor.
make install # pip install -r requirements.txt
make test # offline unit tests
make dry-run # per-source counts, no writes
make run # full pipeline against your local configAdd a provider by extending PRESETS in argus/providers.py. If it speaks the
OpenAI /chat/completions shape, a preset entry is the whole change — no new
adapter, no new dependency.
-
Bump
__version__inargus/__init__.py. -
Add a
## [x.y.z]section toCHANGELOG.md. -
Tag and push:
git tag v1.2.0 && git push origin v1.2.0
The release workflow refuses to publish if the tag disagrees with
__version__, if the tests fail, or if CHANGELOG.md has no matching section.
Be decent to each other. This is a research tool built to save people time — keep the discussion practical and assume good faith.