Content
# HeliosHR Onboarding Automation
When a new hire goes active in Workday, this system provisions their accounts and access across
the SaaS stack (Okta, Google Workspace, Slack, Jira) and opens a Freshservice ticket on failure.
Claude **proposes** the access plan; deterministic policy **disposes** (validates it and decides
whether a human must approve); deterministic orchestration **executes** it idempotently, with a
full audit trail. It is a runnable reference prototype of governed, bounded AI automation, not a
production deployment.
## The thesis (the one idea everything follows from)
**Claude proposes, deterministic policy disposes, deterministic orchestration executes.** The LLM
is a bounded decision-maker: it proposes an access plan and writes a plain-language rationale, but
it never holds final authority over access, never decides approval, never runs an unbounded loop,
and never sees a credential. Everything safety-critical (approval, retries, escalation) is plain,
auditable code.
## Run it (offline, no API key, no real SaaS tenants)
```bash
python3 -m venv .venv && . .venv/bin/activate
pip install -r requirements.txt
PYTHONPATH=src python -m onboarding.run
```
This runs four scenarios end to end and prints the append-only audit trail for each:
1. **Clean joiner** - Engineering birthright, auto-approved, provisioned across all four systems (Okta, Google Workspace, Slack, Jira).
2. **Privileged** - a plan touching `okta-admin` is **held for a human**; provisioning never starts.
3. **Replay** - the same hire event arrives twice; the second pass is idempotent (no duplicate accounts).
4. **Partial failure** - Okta keeps failing; we retry, then **dead-letter** to a Freshservice ticket while the other apps still provision, and mark the worker resumable (we never delete an account we created).
## Tests
```bash
PYTHONPATH=src python -m unittest discover -s tests
```
46 tests covering the model-output validation + repair loop, the governance engine (the ap-payments
regression, SoD, the reconcile guardrail for groups and licenses), provisioning reliability (retry,
idempotency, 409-as-success, dead-letter) across systems, the append-only audit log, and the
orchestrator flows.
## Optional: the live Claude planner
The demo runs offline with a deterministic fallback planner. To use Claude live:
```bash
cp .env.example .env # then put your key in .env (gitignored, never committed)
# set ANTHROPIC_API_KEY=...
. .venv/bin/activate && set -a && . ./.env && set +a
PYTHONPATH=src python -c "from onboarding.planner import propose_plan; ..."
```
The planner uses tool-forced structured output, validates the result against a Pydantic schema,
makes one bounded repair attempt on invalid output, and degrades to the deterministic fallback
(with a visible warning) if the model is unavailable - so a model outage never blocks onboarding.
## Optional: the MCP server
```bash
PYTHONPATH=src python -m onboarding.mcp_server
```
A thin MCP server exposing the same governed provisioning tools (`get_worker`, `onboard_worker`,
`get_onboarding_status`, `open_ticket`) over stdio, so a human in Claude Desktop runs the *same*
audited, approval-gated actions the pipeline does - without ever holding raw Okta keys.
## What is wired vs what is specified
**Wired and runnable (the vertical slice):** the Pydantic contracts, the Claude planner (live +
offline fallback), the deterministic policy engine (reconcile + approval + the `govern` entry
point), idempotent provisioning across all four systems (Okta create+activate as the identity
master, Google Workspace / Slack / Jira as downstream apps) with retry/backoff and dead-letter, the
append-only audit log, the orchestrator state machine, and the MCP server. All four are provisioned
against real-shaped mocks (no live credentials, as the brief expects).
**Specified, not wired (the honest cut-list - "if I had another day"):** swapping the mocks for the
live app APIs and SCIM-via-Okta, the importable n8n workflow JSON, the Mover and Leaver lifecycle
paths, the scheduled drift reconciliation and access recertification, a secrets vault, and
observability dashboards. Each is named in the technical writeup.
## Documents
- [docs/architecture.md](docs/architecture.md) - architecture diagram
- [docs/llm-examples.md](docs/llm-examples.md) - live Claude vs the deterministic fallback (where the LLM earns its place)
- [docs/technical-writeup.md](docs/technical-writeup.md) - technical writeup
- [docs/executive-summary.md](docs/executive-summary.md) - executive summary for non-technical owners
- [docs/ai-usage-statement.md](docs/ai-usage-statement.md) - AI usage statement
## Stack
Python 3.10+, Pydantic v2 (validates all model output), the official `anthropic` SDK (Claude
Sonnet 4.6 planner), and the official `mcp` SDK / FastMCP (the tool gateway). n8n is the intended
orchestration spine in production (HeliosHR's standard); the prototype models that flow as a small,
readable Python state machine.
## Repo layout
```
src/onboarding/
schemas.py canonical contracts (WorkerEvent, AccessPlan)
policy.py deterministic governance (reconcile, approval, govern)
planner.py the Claude Access Planner (live + offline fallback)
provisioning.py idempotent provisioning with retry + dead-letter
mocks.py real-shaped Okta / app (Google/Slack/Jira) / Freshservice fakes
audit.py append-only audit log
orchestrator.py the pipeline state machine
run.py the runnable demo
mcp_server.py the governed MCP tool gateway
tests/ 46 unit tests
```