Safety and policy
The rules that keep an autonomous agent from sending the wrong thing, leaking a secret or acting without a trace.
An agent that can send email and answer phone calls needs limits that do not depend on a model behaving well. JobHunter's limits are written in code and checked deterministically.
Defaults are conservative
- Live crawling and real Gmail sending are off until an operator enables them.
- The phone agent is off by default, and auto-answer is a second, separate switch.
- Tests use a fake email provider and a fixture site. They never touch real mail or a real job board.
Untrusted data stays data
Vacancy text, employer replies and call transcripts come from outside. They are passed to models as data and parsed against schemas. Nothing in them can change a rule, add a recipient or approve a send.
One deterministic gate
Before anything leaves the system, a policy engine checks the application against explicit rules: verified contact, verified resume, no duplicate to the same employer, daily capacity, and whether the employer asked to stop. The model's opinion is an input. It is never the decision.
Everything leaves a trace
Each write operation creates an audit event with an actor and a correlation id. The audit log, JSON logs and Prometheus metrics make it possible to answer what the agent did and why after the fact.
Authentication
| Surface | How it is protected |
|---|---|
| Admin panel | Argon2-hashed admin password and server-side sessions, with ownership checks per user |
| REST API and MCP | A bearer key per client. The server stores only SHA-256 hashes, never the raw keys |
| Gmail | OAuth 2.0 with PKCE, with refresh tokens encrypted at rest |
| Registration | By invitation only |
Revoking an API key means removing its hash from the configuration and restarting the API. A key can be replaced with a short overlap of two hashes.
One level of authority
The built-in bearer mode has a single level of authority: any valid key can call every published tool. The policy engine still prevents a send that breaks the rules. If separate read and write roles are needed, put an OAuth-aware gateway in front of the endpoint.
Secrets
Secrets live in ignored environment files with restrictive permissions. They are never put in a URL, a query string, a repository or a prompt. Raw bearer tokens are held by the client that uses them, and the server cannot recover them.
Health
Readiness is checked on the public endpoint and covers the database and the queue. A degraded phone channel does not fail readiness, so a phone problem never takes the job pipeline offline.