Post

Job Hunter Agent: Governance and Compliance

Light governance for a personal AI agent: who decides, what the platform enforces automatically, licences, LinkedIn's terms, and the evidence that the approval gate holds.

Job Hunter Agent: Governance and Compliance

Governance for a one-person project sounds like theatre, but Job Hunter Agent has two things worth governing: an AI that writes in my name, and a third party (LinkedIn) whose rules I’m bending. The controls are light, and most of them are enforced by code or the platform rather than by discipline.

Project governance

I own the product, the code and the risk. The phase tables in Product planning are the single record of what’s planned and done; this playbook records the decisions and reasons. Changes to the platform side go through pull requests even though I’m the only reviewer, so there’s a dated record of every change to how the app runs.

Decision-making and approval authorities

DecisionWhoRecorded in
Send an applicationMe, per application, in the review queueapplications.approved_at, applied_at
Accept a truthfulness warningMe, explicitly, at approvalNot stored yet (see debt)
Add a source or toolMePhase tables, README
Change the platform setupMe, by merging a PRhomelab-gitops / infra-local history
Change the modelMe, after re-running the evaluationdocs/evaluation.md

Audit requirements

No external audit applies. The internal question I want to answer at any time is “why does this application say that?”, and the data answers it: the original resume, the tailored version, the line edits with their reasons, the warnings, and the agent run that produced them.

Access reviews

Access to the app is membership of Keycloak’s platform-admins group. A quarterly look at that group covers the app and the rest of the platform at once. Keys: the LiteLLM virtual key is limited to one model; the Supabase service key and Slack webhook are in OpenBao, readable only by the platform’s External Secrets.

License management

The app’s own code is private and unlicensed. Its dependencies are open-source (FastAPI, Pydantic, the OpenAI SDK, supabase-py, APScheduler, Authlib, pypdf, python-docx, defusedxml and others), all installed from uv.lock; the SBOM attested with each image lists them. The two third-party pieces that aren’t Python packages:

ComponentLicenceFor this use
mcp-server-linkedin (the LinkedIn MCP server image)Apache-2.0Free to use and run unmodified; the licence covers the code, not LinkedIn’s terms, which still prohibit scraping (see Requirements)
Qwen3.5-35B-A3B model weightsApache-2.0Free to use, including commercially; nothing is redistributed, the model is only served inside the homelab

Compliance reporting

Nothing to report to anyone. The closest thing is the platform’s own compliance: the build gates’ reports are uploaded with each image build, and Kyverno’s admission decisions show the pod meets the platform’s policies.

Data governance

The classification and retention proposals are in Data and Integration. The governing rules: my resume goes only to the local model; other people’s data (contact suggestions) is used only to help me decide whom to contact myself; nothing generated is published without my approval.

Vendor and third-party management

Third partyDependenceExit
LinkedInSource of most postings; terms forbid scrapingAdd postings by hand; Indeed source; stop the profiles
SupabaseDatabase, free tierPostgres anywhere: same migrations, supabase-py swapped for a Postgres repository
mcp-server-linkedin maintainersThe scraperPinned version; fork if abandoned
Wikidata, Google NewsCompany facts and newsOptional; drafts don’t depend on them
SlackRun reportsOptional; email digest already exists

Policy enforcement

Enforced by machines, not by me remembering:

  • Platform (Kyverno, Conftest): signed images from the allowed registry, digest pins, restricted pod security, read-only root filesystem, requests and limits.
  • App: manual approval only (no code path submits anything), a read-only MCP tool allow-list, approval blocked while truthfulness warnings are unresolved, platform-admins checked on sign-in.
  • CI: seven security gates before any image exists.

Evidence collection

If I ever had to show the approval gate works: the transition rules and their tests, the refusal message in the UI, the absence of any submit path in the MCP allow-list (test test_client_lists_tools_and_refuses_account_actions), and each application’s timestamps. For the platform: signed image digests, SBOM attestations, gate reports per build, and Argo CD’s sync history.

Checklist

  • platform-admins membership reviewed quarterly
  • Approvals with accepted warnings recorded
  • Licences of the MCP server and the model noted
  • Exit plan for Supabase tried on a copy once
  • Policy list re-checked when the platform’s Kyverno rules change

This post is licensed under CC BY 4.0 by the author.