Skip to main content

FORMA — AI agent compliance SDK. Zero-config tracking, EU AI Act/DPDP/RBI compliance, cryptographic audit trails.

Project description

FORMA SDK

Make non-compliance impossible — in one line of code.

FORMA doesn't just record what your AI did; it blocks non-compliant decisions before they execute. Add enforce=[...] and PII leaks, prompt injections, and policy violations are stopped at runtime — then every decision is cryptographically signed and mapped to RBI, DPDP, EU AI Act, and ISO 42001.

License: MIT Python 3.8+


Install

pip install forma-sdk

Import name is trustlayer:

import trustlayer as tl

Quickstart — runtime enforcement (zero-touch)

import trustlayer as tl

# One call. Enforcement is process-wide on every LLM/tool call — no decorators,
# no context managers, no edits inside your business logic.
tl.init(
    api_key="tl_live_YOUR_KEY",   # from forma.2bd.net → Settings
    human_sponsor="ops@company.com",
    enforce=["rbi_ml_risk", "dpdp"],   # ← blocks violations BEFORE they run
)

# Your existing code is unchanged.
result = run_underwriting_model(application)

Now, before any LLM or tool call executes:

  • An Aadhaar / PAN / card number in the prompt → blocked (DPDP)
  • "Ignore previous instructions…" / jailbreaks → blocked
  • "Auto-approve without review" → blocked (RBI human-review rule)

A blocked action raises ComplianceViolation, and every decision (allow / warn / block) lands in your signed audit trail. The gate runs locally in ~1 ms — no network hop in your request path.

Multiple agents — tl.register() / agents= (still zero edits)

Map your existing functions to agents without touching their bodies. Each gets its own discrete signed run plus its own enforce / risk_level / compliance / approval config:

import trustlayer as tl
from my_app import approve_loan, validate_kyc, detect_fraud

tl.init(
    api_key="tl_live_YOUR_KEY",
    agents={
        "kyc-validator":  validate_kyc,                                        # bare callable
        "loan-approval":  {"fn": approve_loan, "enforce": ["rbi_ml_risk", "dpdp"],
                           "risk_level": "HIGH"},                              # per-agent config
        "fraud-detector": {"fn": detect_fraud, "enforce": ["dpdp"]},
    },
)

# Equivalent if you register after init:
tl.register("loan-approval", approve_loan, enforce=["rbi_ml_risk"], risk_level="HIGH")

# Call them exactly as before — each is governed and attributed independently.
result = approve_loan(application)

register / agents= work for sync and async def functions and stay correct under 20+ concurrent agents (scope is tracked with contextvars, so threads and asyncio tasks never cross-attribute). They must run before the target is called (top of your entrypoint).

from trustlayer import ComplianceViolation

try:
    result = approve_loan(application)
except ComplianceViolation as e:
    print(e.reason)   # "PII detected in LLM prompt: Aadhaar number. ..."

Zero-config tracking (no enforcement)

import trustlayer as tl
tl.init(api_key="tl_live_YOUR_KEY")

# Every OpenAI / Anthropic / LangChain / LiteLLM call is now auto-captured —
# tokens, cost, latency, anomaly score — with no other code changes.

Human approvals (EU AI Act Article 14 / RBI human review)

import trustlayer as tl

tl.init(
    api_key="tl_live_YOUR_KEY",
    require_approval_when=lambda ctx: ctx.get("amount", 0) > 1_000_000,
    approval_message="Loan above ₹10L requires human review.",
)

# Your existing function runs unchanged — high-stakes calls pause for sign-off.
result = approve_loan(application)

The decision pauses in your FORMA Approvals inbox until a human approves or rejects. Fail-closed: a timeout or unreachable API is treated as a denial — a skipped review never silently passes.


Policy packs

Pack Region Enforces
dpdp India Aadhaar / PAN / card / phone blocked from prompts & tool args; consent-bypass blocked
rbi_ml_risk India Banking auto-approval-without-review blocked; fund-disbursal routed to approval
eu_ai_act EU human-oversight bypass (Art. 14) & logging suppression (Art. 12) blocked; PII protection
iso42001 Global concealing AI involvement blocked

Manual step control (advanced)

Optional. Auto-capture already records every LLM call. Use this only to add non-LLM steps (DB queries, HTTP calls, custom logic) to the timeline — the one case where with tl.using() + tracker.tool_call() is the right tool.

import openai
import trustlayer as tl

tracker = tl.init(api_key="tl_live_YOUR_KEY", auto_capture=False)

def my_agent(task: str) -> str:
    with tl.using("my-agent"):
        with tracker.llm_call(label="generate", model="gpt-4o", prompt=task) as step:
            resp = openai.chat.completions.create(
                model="gpt-4o",
                messages=[{"role": "user", "content": task}],
            )
            step.prompt_tokens     = resp.usage.prompt_tokens
            step.completion_tokens = resp.usage.completion_tokens
            return resp.choices[0].message.content

# For tools:  with tracker.tool_call("send_email", {"to": addr}): ...

Kill switch

Pass kill_switch=True to tl.init(). When you trigger a kill from the dashboard, the next LLM/tool call raises KillSwitchTriggered in under ~100 ms.

CI/CD compliance gate

# Blocks the deploy (exit 1) if any agent is below the threshold
trustlayer gate --pre-deploy --fail-below 80

tl.init() parameters (all 24)

Parameter Description
api_key FORMA API key (or FORMA_API_KEY env).
api_url Backend URL override.
agent_name Display name for ambient auto-captured runs.
human_sponsor Accountable human on the audit record.
auto_capture (True) Auto-patch OpenAI/Anthropic/LiteLLM/LangChain; False = manual llm_call/tool_call.
kill_switch (False) Start global process-level kill-switch watcher.
gate (True) Pre-check every auto-captured call through the compliance gate.
compliance Frameworks for scoring/reports (EU_AI_ACT, DPDP, RBI_MRM, ISO_42001).
ambient_runs (True) Create real signed runs for auto-captured calls.
enforce Policy packs blocked locally pre-execution (dpdp, rbi_ml_risk, eu_ai_act, iso42001).
agents Zero-edit multi-agent map. {"name": fn} or {"name": {"fn": fn, "enforce": [...], "risk_level": "HIGH", ...}}.
purpose Plain-English purpose stored in the identity passport.
risk_level ("MEDIUM") LOW | MEDIUM | HIGH | CRITICAL.
authorized_actions Allow-list of tool names; gate blocks others.
drift_threshold (0.15) Behavioural drift threshold for the passport.
max_cost_usd Hard per-run cost cap; over-budget runs marked failed.
require_approval_when Predicate ctx→bool; True pauses for human approval.
approval_message / approval_title Text in the Approvals inbox.
approval_timeout (3600) Seconds to wait for a decision.
approval_poll_interval (5) Seconds between inbox polls.
approval_via ("forma") Approval channel.
timeout (10) HTTP timeout seconds.
max_retries (2) Transport retry attempts.
fail_closed (False) Block when the gate is unreachable (default fails open).

tl.register(name, fn, **cfg) / agents={...}

Bind an existing function to an agent with no code edits. register re-points the function's name in its defining module to a governed wrapper (and also works as a decorator). agents={...} on tl.init() does the same for a whole map. Both accept the same per-agent keyword arguments as tl.using() below (unknown keyword → TypeError) and support sync + async def.

tl.register("loan-approval", approve_loan, enforce=["rbi_ml_risk"], risk_level="HIGH")
# decorator form:
@tl.register("loan-approval", enforce=["rbi_ml_risk"])
def approve_loan(application): ...

tl.using() parameters (all 15) — advanced manual scoping

tl.using() is the per-agent scoping primitive that register / agents= are built on. Use it directly only to scope an arbitrary block or to instrument manual tracker.tool_call() / tracker.llm_call() steps. It works as a context manager, a sync decorator, or an async decorator.

Parameter Description
name Agent name (positional).
enforce Policy packs (per-scope override).
compliance Frameworks for scoring/reports (per-scope override).
risk_level Risk level (per-scope override).
human_sponsor Accountable human (per-scope override).
purpose Plain-English purpose (per-scope override).
authorized_actions Allow-list of tool names (per-scope override).
max_cost_usd Per-run cost cap (per-scope override).
require_approval_when Approval predicate (per-scope override).
approval_message / approval_title Approvals inbox text (per-scope override).
approval_timeout Seconds to wait (per-scope override).
approval_poll_interval Poll interval seconds (per-scope override).
approval_via Approval channel (per-scope override).
version Agent version label.

kill_switch, gate, auto_capture, ambient_runs, drift_threshold, and agent_name are tl.init() only — passing them to tl.using() raises TypeError.


Node.js / TypeScript

npm install forma-sdk
import * as forma from "forma-sdk";

forma.init({ apiKey: "tl_live_YOUR_KEY", humanSponsor: "ops@company.com" });

const { decision } = await forma.gate("agent-id", {
    actionType: "llm_call",
    prompt: userPrompt,
});

Note: The Node SDK is coming soon (not yet published to npm). Runtime enforcement (enforce) and approvals are Python-only today. The Node package will provide init + gate first; enforcement parity is on the roadmap.


Dashboard & docs

License

MIT — see LICENSE.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

forma_sdk-2.1.0.tar.gz (58.7 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

forma_sdk-2.1.0-py3-none-any.whl (58.7 kB view details)

Uploaded Python 3

File details

Details for the file forma_sdk-2.1.0.tar.gz.

File metadata

  • Download URL: forma_sdk-2.1.0.tar.gz
  • Upload date:
  • Size: 58.7 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.9.6

File hashes

Hashes for forma_sdk-2.1.0.tar.gz
Algorithm Hash digest
SHA256 bfbb7fbe438dbfcab5686f3340f8c1709e2528eba710dde984294a6927d538cc
MD5 99fb44e4f80885b10fda2071b22e6553
BLAKE2b-256 9caa8a6d6bdc307c454d2e3a4b50ac092467f23bfc91f18858910b1d9eb20212

See more details on using hashes here.

File details

Details for the file forma_sdk-2.1.0-py3-none-any.whl.

File metadata

  • Download URL: forma_sdk-2.1.0-py3-none-any.whl
  • Upload date:
  • Size: 58.7 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.9.6

File hashes

Hashes for forma_sdk-2.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 c6ed54924e736229e27b7f03fa3dd43e0eaa00c81eb29679100391034a18a491
MD5 e4e78fe6319668c2423fbe3eab529c7c
BLAKE2b-256 88cc6ce1d08c75e753be7fe6685d89714f97ef16efb9a3f4a37b4919d80b53f8

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page