CoolFace
Apppublic

vanshg1810/corporate-compliance-env

sourceHugging Faceupdated 6mo agoView on Hugging Face
0likes
App README

πŸ›οΈ Corporate Policy Compliance Environment

An OpenEnv-compliant Reinforcement Learning environment that simulates how enterprise compliance officers audit employee expense claims and corporate action requests against internal policy documents.

![OpenEnv Spec](https://openenv.dev) ![Python](https://python.org) ![HuggingFace](https://huggingface.co/spaces/YOUR_USERNAME/corporate-compliance-env) ![License](LICENSE)

πŸ€— Live Space: https://huggingface.co/spaces/vanshg1810/corporate-compliance-env


πŸ“‹ Overview

Every company in the world processes hundreds of expense reports, approval requests, and compliance tickets every day. Today, this requires human auditors who manually read policy documents and make judgement calls. This environment trains an RL agent to do exactly that β€” understand a request, retrieve the relevant policy rule, and make a compliant decision.

This mirrors real production systems used at companies like Ramp, Concur, and SAP β€” but is the first open-source RL training environment for this domain. It is grounded in Indian corporate compliance norms: β‚Ή-denominated limits, GST receipt requirements, WFH allowances, and local travel policies (auto-rickshaw, cab, metro).


🎯 Quick Reference: What The Agent Does

The agent plays the role of a corporate compliance officer. Each episode, it receives one employee expense claim and must decide:

  • β€”βœ… Approve β€” claim follows all policy rules
  • β€”βŒ Reject β€” claim violates policy
  • β€”βš οΈ Escalate β€” claim requires senior review (L7+ employees)

The agent can also:

  • β€”πŸ” SearchPolicy β€” look up relevant rules before deciding
  • β€”πŸ“‹ RequestInformation β€” ask for missing documents

πŸ“‹ The 15 Policy Rules (Quick Reference)

#CategoryRule
1MealUnder β‚Ή500 β†’ Approve, no receipt needed
2Mealβ‚Ή500–₹2,000 β†’ receipt required
3MealOver β‚Ή2,000 β†’ receipt + manager note required
4AlcoholAny alcohol on bill β†’ Reject entire claim
5TravelAuto/metro under β‚Ή500 β†’ no receipt needed
6TravelCab after 10 PM β†’ pre-approved with receipt
7TravelCab before 10 PM β†’ manager note required
8FlightL1–L6 must fly economy β†’ business class = Reject
9FlightL7+ may fly business class β†’ Escalate for review
10InternationalOver β‚Ή50,000 β†’ VP approval required
11WFHInternet + electricity capped at β‚Ή1,000/month
12GSTClaims over β‚Ή5,000 β†’ GST invoice required
13DuplicateSame amount + same date = auto Reject
14SeniorityL7+ employees β†’ always Escalate
15PersonalPersonal expenses β†’ always Reject

πŸ† Baseline Performance

DifficultyTaskLLM Agent (Llama-3.1-8B)Rule-Based Baseline
EasySingle-step classificationβ‰₯ 0.90*0.78
MediumPolicy retrievalβ‰₯ 0.80*0.61
HardMulti-turn contextualβ‰₯ 0.70*0.34

*LLM scores with step-aware prompting (deployed April 2026)


πŸš€ Quick Start

Use the Live Space

Visit the running instance: https://huggingface.co/spaces/vanshg1810/corporate-compliance-env

Run Locally with Docker

bash
# Clone and build
git clone https://huggingface.co/spaces/vanshg1810/corporate-compliance-env
cd corporate-compliance-env
docker build -t compliance-env .
docker run -p 8000:8000 compliance-env

# Validate against OpenEnv spec
openenv validate --url http://localhost:8000 --verbose

Run the LLM Inference Agent

bash
export API_BASE_URL="https://router.huggingface.co/v1"
export MODEL_NAME="meta-llama/Llama-3.1-8B-Instruct"
export HF_TOKEN="your_huggingface_token"

python inference.py

πŸ“‘ API Endpoints (Quick Reference)

EndpointMethodDescription
/healthGETServer health check
/resetPOSTStart a new episode β€’ Body: `{"task_id": "easy\medium\hard"}`
/stepPOSTSubmit an action β€’ Body: ComplianceAction JSON
/stateGETGet current episode state
/tasksGETList all tasks + action schema
/graderPOSTGet final score for completed episode
/baselinePOSTRun baseline agent on all 3 tasks
/docsGETSwagger interactive API documentation

πŸ‘₯ Team

NameRole
Vansh GuptaBackend, Environment Design, Deployment, LLM Agent
SanyaDataset Generation, Policy Rules, Baseline Agent
VedikaQA, Testing, Validation, Bug Fixes

Built for the Meta PyTorch OpenEnv Hackathon 2026.


The agent acts as an AI Compliance Officer. At each step it receives an open "Compliance Ticket" (an expense claim or request) and must:

  1. 1.Understand what the employee is claiming
  2. 2.Search the company policy rulebook if the relevant rule is unknown
  3. 3.Request missing documents from the simulated employee if needed
  4. 4.Resolve the ticket: Approve, Reject, or Escalate

The agent is not handed all information at once. It must earn it β€” mirroring how a real compliance officer navigates incomplete files.


πŸ“¦ Project Structure

corporate-policy-compliance-env/
β”‚
β”œβ”€β”€ app/
β”‚   β”œβ”€β”€ __init__.py           # Exports for RL frameworks (env + client)
β”‚   β”œβ”€β”€ models.py             # All Pydantic schemas
β”‚   β”œβ”€β”€ client.py             # HTTPEnvClient subclass for remote usage
β”‚   β”œβ”€β”€ server/
β”‚   β”‚   β”œβ”€β”€ environment.py    # ComplianceEnv class (reset/step/state)
β”‚   β”‚   └── app.py            # FastAPI app + HF web interface wrapper
β”‚   β”œβ”€β”€ graders.py            # Deterministic grader for all 3 tasks
β”‚   └── baseline.py           # Baseline inference script (OpenAI API)
β”‚
β”œβ”€β”€ data/
β”‚   β”œβ”€β”€ policy.md             # 15-rule company policy document
β”‚   β”œβ”€β”€ claims.json           # 100 synthetic expense claims + ground truth
β”‚   └── generate_dataset.py   # Script to regenerate synthetic data
β”‚
β”œβ”€β”€ tests/
β”‚   └── test_graders.py       # Unit tests for all 3 graders
β”‚
β”œβ”€β”€ openenv.yaml              # OpenEnv metadata file
β”œβ”€β”€ Dockerfile                # Container spec (port 7860)
β”œβ”€β”€ requirements.txt          # Pinned dependencies
└── README.md

🧠 Environment Design

Action Space (ComplianceAction)

The agent takes one of exactly three action types per step:

ActionParametersWhen to Use
SearchPolicyquery: strPolicy rule is unknown β€” search the rulebook
RequestInformationmessage: strDocument is missing from the ticket
ResolveTicketdecision: str, reason: strReady to make final call

Valid decision values: "Approve", "Reject", "Escalate"

Invalid action handling: If the agent sends an unrecognised action_type or missing required fields, the server returns HTTP 400 and applies a -0.1 step penalty. The episode continues.


Observation Space (ComplianceObservation)

At every step, the agent observes:

json
{
  "ticket_id": "EXP-042",
  "employee_name": "Priya Sharma",
  "employee_role": "Junior Engineer",
  "employee_level": "L3",
  "amount": 5000.0,
  "currency": "INR",
  "description": "Client dinner including wine",
  "has_receipt": true,
  "missing_document": "manager_approval",
  "rule_keyword": "entertainment",
  "risk_score": 0.72,
  "env_message": "New ticket received. What is your action?",
  "step_count": 1,
  "max_steps": 8,
  "is_terminal": false
}

Field glossary:

FieldTypeDescription
missing_document`str \null`What document is absent (null if nothing missing)
rule_keywordstrHint for SearchPolicy query (hidden on medium/hard)
risk_scorefloat 0–1Pre-computed risk signal based on amount + role
env_messagestrLatest message from the environment or simulated employee
step_countintSteps taken so far in this episode

State Schema (ComplianceState)

GET /state returns the full mid-episode state:

json
{
  "current_observation": { "...ComplianceObservation fields..." },
  "episode_id": "ep-007",
  "task_id": "hard",
  "steps_taken": 3,
  "actions_history": [
    {"step": 1, "action_type": "SearchPolicy", "query": "entertainment policy"},
    {"step": 2, "action_type": "RequestInformation", "message": "Please share manager approval"}
  ],
  "rewards_history": [0.1, 0.1],
  "cumulative_reward": 0.2,
  "is_done": false
}

Reward Function

Rewards are given at every step β€” not just at the end. This provides a rich training signal over the full trajectory.

EventRewardNotes
Correct ResolveTicket+1.0Full credit for correct final decision
Relevant SearchPolicy+0.1Rule was genuinely unknown at that point
Correct RequestInformation+0.1Document was actually missing
Irrelevant SearchPolicy-0.05Rule was already visible in observation
Asking for info already in ticket-0.2Agent ignored visible context
Wrong ResolveTicket decision-1.0Fatal β€” episode ends immediately
Invalid action format-0.1Malformed action; episode continues
Exceeding max steps-0.5Penalise infinite loops

All rewards are clamped to [-1.0, 1.0] as declared in openenv.yaml.

Episode termination rules:

  • β€”Episode ends immediately on ResolveTicket (correct or wrong)
  • β€”Episode ends if step_count exceeds max_steps for that task
  • β€”Wrong ResolveTicket ends the episode with -1.0 reward
  • β€”All other wrong actions: episode continues, penalty applied

πŸ“Š Tasks

🟒 Task 1 β€” Single-Step Classification (Easy)

Objective: The ticket is fully self-contained. The relevant policy rule is provided directly in the observation. Agent should immediately call ResolveTicket.

  • β€”Max Steps: 3
  • β€”Expected Steps: 1
  • β€”Grader logic:
score = 1.0 if decision == ground_truth_decision else 0.0
  • β€”Example:
Ticket: "Meal expense β‚Ή800, no receipt attached." Policy shown: "Receipts required for meals above β‚Ή500." Correct action: ResolveTicket(decision="Reject")

🟑 Task 2 β€” Policy Retrieval (Medium)

Objective: Ticket is provided but the policy rule is hidden. Agent must call SearchPolicy with the right keyword first, then resolve.

  • β€”Max Steps: 5
  • β€”Expected Steps: 2
  • β€”Grader logic:
searched_policy = any action_type == "SearchPolicy" in episode
correct_decision = final_decision == ground_truth_decision

if correct_decision and searched_policy:     score = 1.0
elif correct_decision and not searched_policy: score = 0.5  # lucky guess
else:                                          score = 0.0
  • β€”Example:
Ticket: "Business class flight Mumbai→Delhi, ₹45,000." Agent must search "flight class policy" to find: "Business class permitted only for VP (L7) and above." Employee role: Manager (L5) → Correct: ResolveTicket(decision="Reject")

πŸ”΄ Task 3 β€” Multi-Turn Contextual Decision (Hard)

Objective: Ticket has a missing document. Agent must identify it, call RequestInformation, evaluate the returned document against policy, and resolve β€” all while weighing employee seniority as a risk factor.

  • β€”Max Steps: 8
  • β€”Expected Steps: 3–4
  • β€”Grader logic (multi-component):
component_scores = {
  "identified_missing_doc":  0.3,  # RequestInformation was correct
  "correct_info_request":    0.3,  # message asked for the right doc
  "correct_final_decision":  0.4   # ResolveTicket matches ground truth
}
score = sum of earned components  # 0.0 to 1.0
  • β€”Example:
Ticket: "International travel β‚Ή1,20,000 β€” no VP approval note." Agent asks: RequestInformation("Please share VP approval for international travel") Environment returns: "Approval mail from VP Rajesh Mehta attached." Agent verifies β†’ ResolveTicket(decision="Approve", reason="VP approval confirmed")

⚠️ Edge Cases

The dataset includes deliberately tricky cases to test grader robustness:

ScenarioAmountRule ThresholdGround TruthWhy Tricky
Meal just under limitβ‚Ή1,999β‚Ή2,000 receipt ruleApproveOne rupee under β€” no receipt needed
Meal just over limitβ‚Ή2,001β‚Ή2,000 receipt ruleRejectOne rupee over β€” receipt required
Auto-rickshaw, no receiptβ‚Ή450β‚Ή500 local travel thresholdApproveBelow threshold; mode allowed
Cab at 11 PMβ‚Ή1,200Night travel policyApproveLate-night cab is explicitly allowed
WFH internet claimβ‚Ή999β‚Ή1,000/month WFH capApproveUnder cap β€” valid WFH expense
Alcohol in restaurant billβ‚Ή3,500Zero alcohol policyRejectAlcohol line item voids entire claim
VP submitting small claimβ‚Ή500Any amount for L7+EscalateHigh-seniority = always escalate
Duplicate claim same dayβ‚Ή2,200Anti-duplication ruleRejectSame employee, same amount, same day

πŸ—‚οΈ Dataset & Policy

data/policy.md β€” 15 Company Rules

The agent's rulebook covers:

  1. 1.Meals under β‚Ή500 β€” no receipt required
  2. 2.Meals β‚Ή500–₹2,000 β€” receipt required
  3. 3.Meals above β‚Ή2,000 β€” receipt + manager approval
  4. 4.Alcohol is never an approved expense category
  5. 5.Local travel (auto/metro) under β‚Ή500 β€” no receipt needed
  6. 6.Cab rides after 10 PM β€” always approved with receipt
  7. 7.Daytime cab rides β€” require manager note
  8. 8.Domestic flights β€” economy class only for L1–L6
  9. 9.Business class β€” permitted for L7 (VP) and above only
  10. 10.International travel above β‚Ή50,000 β€” VP approval mandatory
  11. 11.WFH internet/electricity allowance β€” max β‚Ή1,000/month
  12. 12.Duplicate claims (same employee, amount, date) β€” auto-reject
  13. 13.Any claim from L7+ employee β€” escalate regardless of amount
  14. 14.GST receipt required for all claims above β‚Ή5,000
  15. 15.Personal shopping, gifts, and entertainment without client present β€” reject

data/claims.json β€” 100 Synthetic Claims

json
{
  "id": "EXP-001",
  "employee_name": "Ankit Verma",
  "employee_role": "Junior Engineer",
  "employee_level": "L3",
  "description": "Taxi ride at 2:00 PM without manager note",
  "amount": 800,
  "currency": "INR",
  "has_receipt": true,
  "missing_document": "manager_approval",
  "rule_keyword": "daytime cab",
  "risk_score": 0.65,
  "ground_truth_decision": "Reject",
  "ground_truth_reason": "Daytime cab requires manager approval per policy rule 7"
}

Distribution: 33 Easy / 33 Medium / 34 Hard (100 total claims) Split: 80 training / 20 held-out evaluation

data/generate_dataset.py

Regenerate the full synthetic dataset at any time:

bash
python data/generate_dataset.py --count 100 --seed 42

Parameters: --count (number of claims), --seed (reproducibility), --output (output path). The script uses rule templates + random sampling β€” no external API needed.


βš™οΈ API Endpoints

MethodEndpointDescription
POST/resetStart new episode. Body: `{"task_id": "easy\medium\hard"}`
POST/stepTake one action. Body: ComplianceAction JSON
GET/stateGet current episode state
GET/tasksList all tasks + full action schema
POST/graderGet final score for completed episode
POST/baselineRun baseline agent on all 3 tasks, return scores

/tasks response

json
{
  "tasks": ["easy", "medium", "hard"],
  "action_schema": {
    "action_type": "str β€” SearchPolicy | RequestInformation | ResolveTicket",
    "query": "str | null β€” required for SearchPolicy",
    "message": "str | null β€” required for RequestInformation",
    "decision": "str | null β€” Approve | Reject | Escalate",
    "reason": "str | null β€” required for ResolveTicket"
  }
}

/baseline response

json
{
  "easy":   0.78,
  "medium": 0.61,
  "hard":   0.34,
  "average": 0.577
}

βš™οΈ OpenEnv Spec Compliance

InterfaceReturn TypeStatus
reset()ComplianceObservationβœ…
step(action)obs, reward, done, infoβœ…
state()ComplianceStateβœ…
openenv.yamlMetadata + task listβœ…
openenv validateAll checks passβœ…
/tasks endpointTask list + action schemaβœ…
/grader endpointScore 0.0–1.0βœ…
/baseline endpointScores for all 3 tasksβœ…

πŸš€ Quickstart

1. Clone & Install

bash
git clone https://github.com/your-repo/corporate-compliance-env
cd corporate-compliance-env
pip install -r requirements.txt

2. Run the Server

bash
uvicorn app.server.app:app --host 0.0.0.0 --port 7860

3. Validate Against OpenEnv Spec

bash
openenv validate --host http://localhost:7860

4. Run Baseline Inference

bash
export OPENAI_API_KEY=your_key_here
python app/baseline.py

Expected output:

Task 1 (Easy)   β€” Baseline Score: 0.78
Task 2 (Medium) β€” Baseline Score: 0.61
Task 3 (Hard)   β€” Baseline Score: 0.34
Average Score:    0.577

5. Run Tests

bash
pytest tests/test_graders.py -v

6. Run via Docker

bash
docker build -t compliance-env .
docker run -p 7860:7860 compliance-env

🐳 Dockerfile

dockerfile
FROM python:3.11-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY . .
EXPOSE 7860
CMD ["uvicorn", "app.server.app:app", "--host", "0.0.0.0", "--port", "7860"]

πŸ“„ openenv.yaml

yaml
name: corporate-policy-compliance-env
version: "1.0.0"
description: >
  RL environment simulating enterprise corporate policy compliance.
  An agent audits employee expense claims against a company rulebook
  and decides to Approve, Reject, or Escalate each ticket.
  Grounded in Indian corporate compliance norms (INR, GST, WFH policy).
author: your-name
domain: enterprise-compliance
tags: [compliance, finance, hr, enterprise, india]
reward_range: [-1.0, 1.0]
tasks:
  - id: easy
    name: single_step_classification
    difficulty: easy
    max_steps: 3
    baseline_score: 0.78
  - id: medium
    name: policy_retrieval
    difficulty: medium
    max_steps: 5
    baseline_score: 0.61
  - id: hard
    name: multi_turn_contextual
    difficulty: hard
    max_steps: 8
    baseline_score: 0.34
action_space: ComplianceAction
observation_space: ComplianceObservation

πŸ“ˆ Why This Environment Matters

Companies like Ramp, Concur, and SAP spend millions building proprietary AI auditing systems. This is the first open-source RL training environment for corporate policy compliance β€” enabling any researcher or company to train and benchmark agents for enterprise expense auditing without proprietary data.

Because the policy document is a plain policy.md file, any company can drop in their own rulebook β€” making this a general framework, not just a demo. A well-trained agent on this environment can handle ~70% of routine compliance decisions autonomously.


Built for the Meta Hackathon 2026.