
Enterprise Agent Mesh Engineering Guides · 02/12 · AI-Agent Factory
Build an HR Agent that resolves the employee, jurisdiction, legal entity, employment class and business date before retrieval. Its core product is not a chatbot answer: it is an effective-dated, entitlement-scoped, clause-cited response—or an explicit route to a qualified human when the system cannot safely resolve context.
This guide adapts Article 2 of The Enterprise Agent Mesh — Building Twelve Production AI Agents on Claude Code. It preserves the handbook’s twelve-section structure, its bitemporal policy model, its narrow subagent roles, and its hard rule that sensitive HR decisions stay outside the agent’s authority.
Reference design, not a client case study. Reference-deployment figures, thresholds, model labels and cost numbers in the handbook are retained only where they explain the design; they are not Infinity Technologies client results, current vendor prices or universal benchmarks. Notes marked Web-edition qualification identify engineering hardening or corrections checked against primary sources. Legal precedence, employee-data handling and works-council obligations must be validated for the actual jurisdictions and agreements. Technical references checked 15 September 2026.
Context resolution is an authorization step. Retrieval does not begin until the system can prove which policy set applies to which employee, for which business date.
The Header illustration is the shared Agent Mesh platform boundary, not an HR product screenshot. The concrete HR data flow, bitemporal model and policy gates are specified below.
The Recruitment Agent stops at the signed offer. The HR Agent starts there and stays with the employee lifecycle through onboarding, policy support, leave, performance-cycle support, organisational change, offboarding and the retention window. That boundary matters: the HR Agent has deeper access to employee context, but it also has more situations in which the correct action is to stop reasoning and route.
| Workflow | Reference posture | Permanent or promoted boundary |
|---|---|---|
| In-force policy Q&A, no CBA | L3 act-and-notify | Only after evaluated citation validity and staleness gates; no free-form policy source. |
| Retroactive or CBA-covered policy Q&A | L1 draft | May reach L2 with demonstrated HRBP acceptance; precedence remains reviewable. |
| Leave / absence calculation | L2 act-with-approval | Numbers come from the leave calculator; promotion requires payroll parity evidence. |
| Onboarding orchestration | L3 | L4 only for bounded IT/facilities tasks in the handbook reference; employment decisions stay out. |
| Offboarding | L2 | Hard ceiling. Access revocation and employment-status changes require separate authority. |
| Performance-cycle support | L1 | Hard ceiling. Review writing quality; never generate or alter a rating. |
| Case triage and routing | L3 | Classify and route; sensitive content becomes route-only. |
| Org-change impact analysis | L0 suggest | Impact assembly only; no decision or employee communication. |
The handbook describes six business workflows: policy Q&A, onboarding/offboarding orchestration, absence and leave calculation, performance-cycle support, org-change impact analysis, and case triage/routing. It reports reference-deployment targets such as deflecting 65–70% of Tier-1 policy questions and improving day-one readiness from 71% to 96%. Those numbers are useful as examples of measurable outcomes; a deployment must establish its own baseline, error cost and acceptance criteria.
The hard prohibitions are more important than the target metrics. The agent does not generate or modify performance ratings, decide or communicate termination, determine reasonable accommodation, write compensation or employment-status fields, reason over health details rather than routing them, or generate per-employee behavioural analytics without the required governance. Promotion up the autonomy ladder is earned by evaluated evidence and a named configuration approval, not by model confidence.
The architecture is built around one sequencing invariant: resolve before retrieve. A policy corpus can contain several simultaneously plausible answers—global policy, entity addenda, collective agreements, works-council agreements, statutory summaries and past versions. Vector similarity has no concept of which one is applicable to this employee on this date. The system therefore resolves context deterministically before a retrieval query exists.
Slack / Teams / portal message
-> hr-case-triage (fixed sensitivity labels)
-> subject binding: requester vs named employee
-> policy-query-planner
-> resolve_employee_context(employee_id, as_of_date)
-> assignment history when the period spans a move
-> structured retrieval plan
-> bitemporal policy_search(
policy_set_ids,
business_date,
transaction_time,
resolved principals)
-> precedence-resolver only when corpus classes conflict
-> cited answer OR abstain / route
-> evidence ledger
Onboarding / offboarding:
durable task graph -> NATS events -> bounded system adapters
consequential write -> separately authorised execution pathThe session correlation key includes the subject employee as well as the conversation/thread identity. If a manager joins a thread that began as “my leave” and asks about a direct report, the employee subject changes and the context must fork. Reusing the original retrieved clauses is a privacy and correctness bug, not a conversational convenience.
The orchestrator uses four named subagents from the source: hr-case-triage, policy-query-planner, precedence-resolver and feedback-quality-reviewer. The first is classification; the second turns a question into a context-resolved retrieval plan; the third handles genuinely conflicting policy instruments; the fourth reviews manager feedback for unsupported generalisations and problematic language without generating or adjusting a performance rating.
Inter-agent work remains event-based. Onboarding tasks should not become a nested chain of LLM calls into IT, Finance or other business agents. Events retain independent identity, retry, ACL, cost and evidence-ledger boundaries. The precedence resolver is different: it is an internal specialist within one HR answer, so its result belongs inline in the same decision boundary.
hr-agent/
CLAUDE.md
.mcp.json
.claude/
agents/
policy-query-planner.md
precedence-resolver.md
hr-case-triage.md
feedback-quality-reviewer.md
skills/
leave-entitlement/{SKILL.md,reference.md,accrual_rules.yaml}
calibration-packet/{SKILL.md,reference.md}
hooks/
hr-policy-gate.py
subject-binding.py
settings.json
mcp/
hris/server.py
corpus/server.py
evals/
golden/policy_matrix.jsonl
golden/must_abstain.jsonl
rubrics/hr_answer_judge.json
migrations/Stable invariants belong in CLAUDE.md; procedural steps belong in skills; jurisdiction lists, policy text, escalation contacts and other changing facts belong behind tools or retrieval. This separation lets a policy change, a workflow change and a model change move through independent review and evaluation paths.
# HR Agent — operating invariants (web-edition excerpt)
## Resolve before retrieve
Never search policy for an employee until resolve_employee_context succeeds.
ambiguous | not_found | error -> route to an HRBP; never infer jurisdiction.
## Two time axes
business_date = when the rule applies.
transaction_time = what the organisation knew when the answer was given.
Never silently replace an unknown business date with "today".
## Numbers come from deterministic tools
Leave balances, accruals, service dates, proration and notice calculations
come from HRIS / compute_leave_entitlement. No arithmetic in prose.
## Hard stops
Termination, discipline, grievance, investigation, accommodation, and
special-category / criminal-matter content -> acknowledge minimally and route.
## Citations
Every entitlement or quantitative claim carries clause_id, clause_ref,
policy-set version and the business date for which that clause is valid.Web-edition qualification — “never default to today” needs an interface contract. The source intentionally fails closed on an unspecified business date. A production UX may explicitly offer “current policy as of today” as a user-selected intent, but that date must become a typed input before retrieval. The defect is a silent temporal assumption, not the word “today” itself.
The handbook gives a baseline policy precedence of statute > collective agreement > works-council agreement > entity policy > global handbook, then adds exceptions such as employee-favourability principles and scope/silence rules. Treat that precedence as jurisdiction-specific configuration reviewed by employment counsel, not universal law encoded forever in a prompt.
Each specialist has a narrow tool surface and returns a machine-checkable artifact. Validate the exact frontmatter fields against the official Claude Code subagent reference for the deployed version.
---
name: policy-query-planner
description: Resolve subject, policy context and business date; emit a retrieval plan.
tools: mcp__hris__resolve_employee_context, mcp__hris__get_assignment_history
disallowedTools: Write, Edit, Bash, mcp__corpus__*
model: sonnet
maxTurns: 6
permissionMode: default
---
Do not answer and do not retrieve.
1. Bind the subject employee from authenticated context.
2. Determine business_date or a range; otherwise request clarification.
3. Resolve context at each boundary of the range.
4. If entity/country/class changes, split the period into segments.
5. Emit structured JSON: subject, dates, segments, topics,
transaction_time, clarification_needed.A manager or HRBP asking about another employee needs an authenticated subject identifier passed by the surrounding application. Free text such as “what about Anna?” cannot by itself select an employee record.
---
name: precedence-resolver
description: Resolve conflicting clauses for one topic and one resolved policy set.
tools: mcp__corpus__policy_search, mcp__corpus__get_clause
disallowedTools: Write, Edit, Bash
model: opus
maxTurns: 10
permissionMode: default
---
For every candidate clause, fetch the full clause before resolving.
Apply the approved jurisdiction-specific precedence and favourability policy.
Same-rank or legally ambiguous conflicts -> verdict: unresolvable | needs_legal.
Return governing clause, displaced clauses, and the reasoning trace.Retrieval chunks are discovery artifacts, not authoritative legal units. If the exception sits outside a chunk boundary, the resolver must read the complete clause before making a precedence judgement.
---
name: hr-case-triage
description: Classify inbound HR content before any policy retrieval.
tools: mcp__hris__get_hrbp_for_employee
disallowedTools: Write, Edit, Bash, mcp__corpus__policy_search
model: haiku
maxTurns: 3
permissionMode: default
---
Output one of:
standard | restricted | interlocked | special_category | criminal_matter.
Anything except standard is route_only.
Low confidence escalates sensitivity; it never downgrades it.Web-edition qualification — operational labels are not legal definitions. GDPR Article 9 enumerates special categories including health data, trade-union membership, racial or ethnic origin and sexual orientation; criminal-conviction/offence data is addressed separately in Article 10. A company may route a broader set of content conservatively, but should not mislabel every such case as automatically Article 9 data.
The fourth role is bounded to performance-cycle language. It can flag recency-bias wording, unsupported generalisations or protected-characteristic references and assemble a review packet. It cannot create or alter a rating, predict performance or convert writing-quality flags into an employee score.
The source’s main example is leave-entitlement. The skill assembles inputs and explains results; the calculator performs the arithmetic. This makes accrual and statutory-floor logic testable without asking a language model to reproduce date arithmetic.
---
name: leave-entitlement
description: Explain a leave entitlement from a resolved employee context.
allowed-tools: mcp__hris__resolve_employee_context, mcp__leave__compute_leave_entitlement, Read
user-invocable: true
context: fork
arguments: [employee_id, absence_type, as_of_date]
paths: "hr/leave/**"
---
Required before the tool call:
- resolved entity, country, class, CBA/works-council policy set
- FTE, continuous-service start, contractual hours
- one canonical absence type
- explicit as_of_date
compute_leave_entitlement returns:
entitlement, unit, accrued, taken, booked, balance,
proration_basis, carryover_expiry, clause_ids.
If clause_ids fall outside the resolved policy_set_ids:
stop and raise agent.hr.calc.mismatch.
Never round and never convert days/hours in prose.The official Agent Skills reference documents arguments, allowed tools and forked contexts. Keep a short contract in SKILL.md and load long jurisdiction-specific interaction rules only when required.
Any live statutory-floor lookup shown in the handbook should be implemented as a typed, reviewed tool boundary in production. Do not concatenate user-controlled values into shell or SQL and treat that as an enterprise control.
The HR Agent fronts HRIS, payroll, case-management, identity, learning and collaboration systems. Put vendor-specific transport quirks inside adapters so the agent calls stable canonical operations even when one tenant needs SOAP/RaaS and another uses REST.
| Boundary | Canonical capability | Write posture |
|---|---|---|
| HRIS adapters | resolve employee context, read worker and assignment history | Read-only for policy answering; no compensation/status mutation. |
| Payroll | authoritative metadata and parity checks | Read-only in reasoning path. |
| ServiceNow / Jira Service Management | create/update routed cases | Idempotent scoped writes; sensitive cases require configured human acceptance. |
| Okta / Entra ID | read memberships; propose provisioning/deprovisioning tasks | Consequential writes behind separate approval and downstream entitlement checks. |
| LMS | read assignments; prepare bounded assignments | Policy-gated writes only. |
| Slack / Teams | message ingress and safe response delivery | Subject binding and privacy rules enforced outside the model. |
{
"mcpServers": {
"hris": {
"type": "http",
"url": "${AGENT_GATEWAY_URL}/hris/mcp",
"headersHelper": "/opt/agent-platform/bin/get-mcp-auth-headers.sh"
},
"corpus": {
"type": "stdio",
"command": "uv",
"args": ["run", "--directory", "${CLAUDE_PROJECT_DIR}/mcp/corpus", "server.py"]
},
"itsm": {
"type": "http",
"url": "${AGENT_GATEWAY_URL}/servicenow/mcp",
"headersHelper": "/opt/agent-platform/bin/get-mcp-auth-headers.sh"
},
"leave": {
"type": "stdio",
"command": "uv",
"args": ["run", "--directory", "${CLAUDE_PROJECT_DIR}/mcp/leave", "server.py"]
}
}
}Web-edition qualification — headersHelper is not “per-call token minting” by itself. The current Claude Code MCP documentation describes helper execution when the connection is established and on reconnection. Keep request-level authorization and token-exchange semantics in the gateway/downstream layer and test expiry/revocation on long-lived connections.
resolve_employee_context is a security primitiverequest:
employee_id: EMP-opaque-id
as_of_date: 2026-03-12
result:
resolution_status: resolved | ambiguous | not_found
legal_entity: entity-id
country: PL
work_location: location-id
employment_class: permanent
cba_ids: [...]
works_council_ids: [...]
policy_set_ids: [...]
manager_chain: [...]
context_token: short-lived signed tokenThis is a deterministic tool, not semantic retrieval. Concurrent assignments, a pending transfer or missing coverage data produce ambiguous. The context token binds later policy search to the exact resolved keys, turning context resolution into authorization evidence.
The policy corpus contains policies, entity addenda, collective agreements, works-council agreements, counsel-maintained statutory summaries and process guides. It does not contain employee records, case notes, performance content, compensation data or leave-case files; those remain behind row/field-entitled tools.
Business time answers “when did this rule apply?” Transaction time answers “when did the organisation know this version?” Both are required to reproduce historical advice after a retroactive agreement or correction.
CREATE EXTENSION IF NOT EXISTS btree_gist;
CREATE TABLE policy_clause (
clause_id BIGSERIAL PRIMARY KEY,
tenant_id UUID NOT NULL,
policy_set_id TEXT NOT NULL,
corpus_class TEXT NOT NULL,
jurisdiction TEXT NOT NULL,
clause_ref TEXT NOT NULL,
topic TEXT[] NOT NULL,
content TEXT NOT NULL,
acl_principals TEXT[] NOT NULL,
effective_from DATE NOT NULL,
effective_to DATE NOT NULL DEFAULT DATE '9999-12-31',
recorded_from TIMESTAMPTZ NOT NULL DEFAULT now(),
recorded_to TIMESTAMPTZ NOT NULL DEFAULT 'infinity',
supersedes BIGINT REFERENCES policy_clause(clause_id),
content_sha256 BYTEA NOT NULL,
CONSTRAINT bitemporal_no_overlap EXCLUDE USING gist (
tenant_id WITH =,
policy_set_id WITH =,
clause_ref WITH =,
daterange(effective_from, effective_to, '[)') WITH &&,
tstzrange(recorded_from, recorded_to, '[)') WITH &&
)
);The half-open [) convention avoids double-validity at a version boundary. PostgreSQL documents range bounds and exclusion constraints in the range-type reference, while btree_gist supplies GiST operator classes for scalar columns used beside ranges. Corrections close the old transaction interval and insert a new row rather than rewrite history.
WITH visible AS (
SELECT * FROM policy_clause
WHERE tenant_id = $tenant
AND policy_set_id = ANY($policy_sets)
AND acl_principals && $principals
AND $business_date::date >= effective_from
AND $business_date::date < effective_to
AND $txn_time::timestamptz >= recorded_from
AND $txn_time::timestamptz < recorded_to
)
-- dense + lexical retrieval run only over visible rows
-- fuse candidates, rerank, then enforce precedence presenceACL, policy-set, jurisdiction and both time axes are SQL predicates before ranking. Post-filtering a global top-k is unsafe: the wrong jurisdictions compete for slots and restricted clauses may enter intermediate context.
The handbook’s sample query uses PostgreSQL full-text ranking (ts_rank_cd) as its lexical branch plus dense retrieval, reciprocal-rank fusion and reranking. This edition calls that branch lexical full-text retrieval, not BM25; a tsvector/ts_rank_cd implementation should not be relabelled BM25 unless the deployed lexical engine actually implements BM25.
Chunk policies at clause/article boundaries, not a fixed token window. After reranking, enforce a precedence-presence guard: when a higher-precedence candidate exists for the topic and is missing from final evidence, fail closed rather than answer. The source’s recall/nDCG/grounding values are reference gates, not production guarantees.
The strongest controls live below the prompt. Policy clauses are filtered by caller principals; HRIS adapters project only entitled fields; write credentials are absent from policy-answering workers.
# PreToolUse policy contract — reference logic
if tool.startswith("mcp__corpus__"):
require(valid_context_token)
require(explicit_business_date)
require(single_resolved_segment)
if sensitivity in {"special_category", "criminal_matter"}:
allow_only("mcp__itsm__create_case")
if topic in {"termination", "redundancy", "discipline",
"grievance", "investigation", "accommodation",
"whistleblowing"}:
require(hrbp_case_acceptance)
if tool in PER_EMPLOYEE_MONITORING_TOOLS:
require(applicable_worker_representation_approval)Enforce the same policy in service authorization. Any scratchpad or state consulted by a hook must be integrity-protected and bound to the authenticated session; otherwise “resolved” state can be forged.
GDPR Articles 9 and 10 distinguish special categories of personal data from criminal-conviction/offence data. Concrete lawful bases, employment-law exceptions, minimisation and retention rules remain deployment-specific.
For Germany, BetrVG §87(1)(6) covers co-determination concerning technical devices intended to monitor employee behaviour or performance. Whether a specific analytic feature falls within the rule depends on actual facts, so implement a configurable governance check rather than a universal prompt shortcut.
Offboarding is segregated structurally. The HR Agent may prepare a revocation plan; consequential identity or employment-status execution uses a separately authorised principal and downstream entitlement validation. A model-supplied manager ID is not approval.
Run bounded headless workers around durable business state. For multi-turn policy conversations, bind an application-level subject_session_key to the actual SDK session identifier returned by the runtime. A subject change creates a new application key.
from hashlib import sha256
from claude_agent_sdk import ClaudeAgentOptions
def options_for(event, resumed_sdk_session_id=None):
kwargs = dict(
model=event["approved_model"],
system_prompt={"type": "preset", "preset": "claude_code"},
setting_sources=["project"],
allowed_tools=[
"mcp__hris__resolve_employee_context",
"mcp__hris__get_assignment_history",
"mcp__corpus__policy_search",
"mcp__corpus__get_clause",
"mcp__leave__compute_leave_entitlement",
"mcp__itsm__create_case",
],
disallowed_tools=["Bash", "Write", "Edit", "WebSearch"],
permission_mode="default",
max_turns=24,
max_budget_usd=event["turn_budget_usd"],
)
if resumed_sdk_session_id:
kwargs["resume"] = resumed_sdk_session_id
return ClaudeAgentOptions(**kwargs)
subject_session_key = sha256(
f"{channel}|{thread_id}|{subject_employee_id}".encode()
).hexdigest()Web-edition qualification — session continuation. The source excerpt passes session_id directly to ClaudeAgentOptions. The current Python Agent SDK reference documents resume / conversation continuation. Treat the subject-bound key as application state mapped to an actual SDK session identifier and verify the concrete SDK version before copying the excerpt.
Budget/turn caps are circuit breakers, not product economics. The source’s example USD cap and p50/p99 costs are reference-deployment figures. A turn that fails context resolution should route instead of iterating indefinitely.
Case creation needs stable idempotency derived from subject, topic, business date and versioned policy/prompt inputs. Long onboarding/offboarding flows belong in durable workflow state; the agent is called for judgement and explanation, not used as the task database.
The source builds a jurisdiction × business-date × topic matrix: roughly 400 reference cases plus a dedicated must-abstain set. The expensive artifact is the clause-by-clause human/counsel validation of what should govern each case.
| Metric | What it catches | Handbook reference gate |
|---|---|---|
| Answer correctness | Wrong entitlement value/unit on answerable items | Target ≥0.93. |
| Abstention quality | Agent answers cases that should route | Target ≥0.97; blocking. |
| Over-abstention | Safe questions unnecessarily routed | ≤0.08. |
| Citation validity | Clause invalid for asserted time context | ≥0.99; blocking. |
| Staleness | Expired/superseded clause treated as governing | 0; blocking. |
| Precedence correctness | Local/CBA/statutory override mishandled | ≥0.95 on dedicated slice. |
| Jurisdiction purity | Answer blends policy contexts in a non-comparative question | 0; blocking. |
| Retrieval recall@40 | Correct clause absent before rerank | ≥0.97 reference target. |
Weight abstention errors heavily. A system that answers more questions with plausible, cited, wrong policy is worse than one that safely routes uncertainty. Build must-abstain cases around ambiguity, unresolved conflicts, sensitive topics, cross-jurisdiction periods, unavailable calculators and missing policy.
Citation validity, staleness, context-token binding and jurisdiction purity are deterministic assertions. Do not use an LLM judge where a database query can settle the question. Use a judge only for bounded qualitative criteria, and validate the judge against human labels.
A short local addendum can lose to a long, semantically rich global section. Retrieve only from the resolved policy set and use the precedence-presence guard after reranking.
A historical question gets today’s policy because business_date defaulted silently. Make it explicit and keep retroactive/future-dated cases in CI.
A period spans a country/entity move and the model combines one jurisdiction’s floor with another’s agreement. Split assignment history into segments and answer each independently.
Queries about absence patterns, feedback wording and discipline can become a sensitive pattern over several weeks. Single-turn classification is insufficient; use application-level pattern detection, HR routing and an auditable trail.
The subject changes to a direct report while old employee context is resident. Subject-bound session identity and context tokens must make that continuation impossible.
A model calculates proration inline and produces a plausible but payroll-inconsistent number. All entitlement arithmetic comes from the calculator; negative tests reject any number not present in authoritative results.
Stand up the bitemporal table/exclusion constraint, load one policy set and local addendum, implement context resolution against HRIS and make ambiguity fail closed. Write the first forty golden cases.
Add the planner, corpus MCP service and SQL-enforced ACL/time filters. Put triage in front of every request. Pilot L1 draft answers with a small HRBP group that sees the clauses and sends the final response. Grow the matrix across several jurisdictions.
Add CBA/works-council corpora and precedence resolution. Promote only narrow Q&A after the deployment’s own citation/staleness gates hold. Add leave calculation at L2 and run payroll parity before trusting numbers. Start onboarding orchestration last, after durable workflow semantics and reconciliation exist.
The source sequence is a reference build order, not a delivery commitment. Production needs named owners for policy ingestion, legal review, HRIS identity/entitlements, retention, incident handling and evaluation approval.
Primary source: Article 2, “The HR Agent: Effective-Dated, Jurisdiction-Scoped Policy Retrieval”, plus the shared-platform conventions in The Enterprise Agent Mesh — Building Twelve Production AI Agents on Claude Code, September 2026. This web edition preserves its twelve-section architecture, named subagents, bitemporal corpus, context-resolution tool, guardrails, evaluation matrix and build order.
Explicit web-edition qualifications: legal precedence is reviewed jurisdiction-specific configuration; GDPR Article 9 and Article 10 categories are distinguished; works-council monitoring is linked to statutory text rather than generalized globally; headersHelper is described with current connection/reconnection semantics; session continuation is adapted to the SDK’s documented resume mechanism; PostgreSQL lexical ranking is not mislabeled BM25; and source deployment numbers remain examples, not Infinity client outcomes.
This is guide 02/12 in the business-function Enterprise Agent Mesh / AI-Agent Factory series, separate from InfinitySDLC.
Previous: Recruitment Agent — Evidence Assembly Under a High-Risk Regulatory Regime.
Next: Supply Chain Agent — Exception Narratives Over an Optimiser You Already Own. The next guide is forthcoming; no unpublished page is linked here.










.png)
.png)
