Ariadne opens a pull request when it can: the repository is mapped, the file is in the write allowlist, and the change is one anchored snippet the validator can check. When any of that fails the incident escalates with a diagnosis and nothing else - even though the model that wrote the diagnosis frequently knows exactly what the fix is. That knowledge was discarded at the moment it was most useful, because the cases where no patch is possible are exactly the cases a maintainer has to do by hand. A diagnosis may now carry up to three code suggestions: the file, what is wrong there, and the code to change it to. Rendered into the issue under a heading that says the change was not applied, because a code block in an issue reads like something that already happened unless it is told otherwise. Deliberately not a patch, and the difference is the safety story. A patch must survive the validator because Ariadne acts on it. A suggestion is read by a person who is already going to edit that file, so being wrong costs them a moment's thought rather than a bad commit - which is why suggestions may describe changes too large or too diffuse for the patcher to have attempted, and why nothing here is anchored, applied or pushed. Bounded at three. A diagnosis that suggests a dozen changes has stopped diagnosing and started rewriting, and an issue that long buries the reason a person was called in the first place. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
ariadne
Ariadne is the Atlas admin and account automation service.
It sits behind the portal and handles the jobs that are annoying or risky to do by hand: approving access, syncing account state, rotating service passwords, cleaning stale Kubernetes work, checking platform health, and keeping a few service integrations lined up.
How it works
Ariadne is a FastAPI service with a small scheduler. It talks to Keycloak, Vault, Mailu, Nextcloud, Wger, Firefly, Jenkins, Metis, Kubernetes, and a few Atlas-specific services through focused adapters under ariadne/services/.
The API is split between admin routes, account self-service routes, internal event hooks, and Prometheus metrics. Background jobs store run history in the Ariadne database so failures can be inspected later instead of vanishing into logs.
The following are notes for future Brad.
Bring-up dependencies
Ariadne needs:
- Kubernetes API, service DNS, and Ariadne's service account/RBAC
- the Ariadne database, plus the portal database if portal/account sync is enabled
- Vault or the Kubernetes secrets that Vault normally feeds it
- Keycloak/OIDC, because auth and profile sync assume it exists
- ingress/proxy plumbing if humans are going to use it through the portal
- the services for whatever jobs are enabled: Mailu, Nextcloud, Vaultwarden, Wger, Firefly, Jenkins, Metis, OpenSearch, and the comms/game-mode pieces
It can start before every integration is perfect, but the matching scheduled jobs will fail or no-op until their service is actually alive. In a total bring-up, wait for storage, Flux, Postgres, Vault, Keycloak, and ingress first. Afterwards Ariadne becomes useful glue.
Useful routes:
GET /healthGET /metricsGET /api/admin/cluster/statePOST /api/admin/access/requests/{username}/approvePOST /api/account/mailu/rotatePOST /api/account/wger/resetPOST /api/account/firefly/resetPOST /events
Development
python -m pytest
ruff check .
Most runtime behavior is configured through environment variables in ariadne/settings.py. Service-specific logic is in the small adapter modules; ariadne/app.py is focused on request flow and task orchestration.