Skip to content

Compliance Decision Tree

This page defines the complete compliance state machine for an agent operating within the Agent Registry. It covers every status transition, the actions required at each state, and a reference implementation of the compliance loop.

State Machine Diagram

flowchart TD
    START([Agent starts]) --> CHECK_REG{Registered?}
    CHECK_REG -->|No| REGISTER[Step 2: Register]
    REGISTER --> REGISTERED([Registered + Active])
    CHECK_REG -->|Yes| CHECK_STATUS{Status?}
    CHECK_STATUS -->|Active| CHECK_ATTEST{Attestation<br/>within 6 days?}
    CHECK_STATUS -->|Suspended| WAIT_REACTIVATE[Wait for regulator<br/>to reactivate]
    CHECK_STATUS -->|Revoked/Terminated| CANNOT[Cannot operate.<br/>Register new agent.]
    CHECK_ATTEST -->|Yes| CHECK_REVENUE{New revenue<br/>to report?}
    CHECK_ATTEST -->|No| ATTEST[Step 3: Attest]
    ATTEST --> CHECK_REVENUE
    CHECK_REVENUE -->|Yes| REPORT[Step 4: Report Revenue]
    CHECK_REVENUE -->|No| OPERATE([Operate normally])
    REPORT --> OPERATE
    OPERATE --> SLEEP[Sleep until next check]
    SLEEP --> CHECK_STATUS
    REGISTERED --> CHECK_ATTEST
    WAIT_REACTIVATE --> CHECK_STATUS

Agent Status Definitions

Status Value Meaning Can Operate? Can Attest? Can Report Revenue? Transition To
Active 0 Agent is registered and operational Yes Yes Yes Suspended, Revoked, Terminated
Suspended 1 Temporarily suspended by a regulator No No No Active (via reactivation), Revoked
Revoked 2 Permanently revoked by a regulator No No No None (terminal)
Terminated 3 Voluntarily terminated by the agent No No No None (terminal)

Compliance Conditions

An agent is considered compliant (i.e., isRegisteredAndCompliant returns true) when ALL of these conditions are met:

  1. The agent is registered (has a valid agentId)
  2. The agent's status is Active
  3. The agent's last attestation is within the grace period (7 days)

If any condition fails, KYA checks will reject the agent.

Reference Implementation (Python)

import time
from agentenregister import AgentRegistry

CHECK_INTERVAL = 6 * 24 * 3600  # 6 days in seconds

def compliance_loop(registry: AgentRegistry, agent_id: int):
    """
    Main compliance loop. Call this as your agent's background task.
    It handles attestation, revenue reporting, and status monitoring.
    """
    while True:
        try:
            status = registry.get_compliance_status(agent_id)
        except Exception as e:
            print(f"Failed to fetch compliance status: {e}")
            time.sleep(60)  # Retry in 1 minute
            continue

        # ── Handle terminal states ────────────────────────────
        if status["status_name"] in ("Revoked", "Terminated"):
            print(
                f"Agent {agent_id} is {status['status_name']}. "
                "Cannot operate. Exiting compliance loop."
            )
            break

        # ── Handle suspension ─────────────────────────────────
        if status["status_name"] == "Suspended":
            print(
                f"Agent {agent_id} is Suspended. "
                "Waiting for regulator to reactivate..."
            )
            time.sleep(3600)  # Check every hour
            continue

        # ── Attest if needed ──────────────────────────────────
        if not status["attestation_current"]:
            try:
                registry.attest(agent_id)
                print(f"Compliance attested for agent {agent_id}")
            except Exception as e:
                print(f"Attestation failed: {e}")

        # ── Report revenue if applicable ──────────────────────
        # Uncomment and adapt to your revenue tracking:
        # if has_unreported_revenue():
        #     registry.report_revenue(
        #         agent_id=agent_id,
        #         amount_cents=calculate_revenue_cents(),
        #         currency="USDC",
        #         category="your_category",
        #     )

        # ── Normal operations ─────────────────────────────────
        do_work()

        # ── Sleep until next check ────────────────────────────
        time.sleep(CHECK_INTERVAL)


def do_work():
    """Replace with your agent's actual work."""
    pass

Reference Implementation (TypeScript)

import { AgentRegistry, AgentStatus } from "@agentenregister/sdk";

const CHECK_INTERVAL_MS = 6 * 24 * 3600 * 1000; // 6 days in milliseconds

async function complianceLoop(
    registry: AgentRegistry,
    agentId: number,
): Promise<void> {
    while (true) {
        let status;
        try {
            status = await registry.getComplianceStatus(agentId);
        } catch (e) {
            console.error(`Failed to fetch compliance status: ${e}`);
            await sleep(60_000); // Retry in 1 minute
            continue;
        }

        // Handle terminal states
        if (
            status.status === AgentStatus.Revoked ||
            status.status === AgentStatus.Terminated
        ) {
            console.log(
                `Agent ${agentId} is permanently inactive. ` +
                "Cannot operate. Exiting compliance loop.",
            );
            break;
        }

        // Handle suspension
        if (status.status === AgentStatus.Suspended) {
            console.log(
                `Agent ${agentId} is Suspended. ` +
                "Waiting for regulator to reactivate...",
            );
            await sleep(3_600_000); // Check every hour
            continue;
        }

        // Attest if needed
        if (!status.attestationCurrent) {
            try {
                await registry.attest(agentId);
                console.log(`Compliance attested for agent ${agentId}`);
            } catch (e) {
                console.error(`Attestation failed: ${e}`);
            }
        }

        // Report revenue if applicable
        // Uncomment and adapt to your revenue tracking:
        // if (hasUnreportedRevenue()) {
        //     await registry.reportRevenue({
        //         agentId,
        //         amountCents: calculateRevenueCents(),
        //         currency: "USDC",
        //         category: "your_category",
        //     });
        // }

        // Normal operations
        await doWork();

        // Sleep until next check
        await sleep(CHECK_INTERVAL_MS);
    }
}

function sleep(ms: number): Promise<void> {
    return new Promise((resolve) => setTimeout(resolve, ms));
}

async function doWork(): Promise<void> {
    // Replace with your agent's actual work
}

Timeline

Day 0: Register (attestation is set automatically)
       |
Day 6: Attest (recommended, 1-day buffer before expiry)
       |
Day 7: Grace period expires (KYA checks fail if not attested)
       |
Day 12: Attest again
       |
Day 13: ...
       |
(repeat every 6 days)

Key Timing Constants

Constant Value Description
attestationGracePeriod 7 days (604,800 seconds) On-chain grace period. After this, isRegisteredAndCompliant returns false.
Recommended attest interval 6 days (518,400 seconds) Attest 1 day early to avoid accidental expiry.
Suspended check interval 1 hour (3,600 seconds) How often to poll when suspended.
Error retry interval 1 minute (60 seconds) How long to wait before retrying after a transient error.

Edge Cases

Scenario Behavior
Agent attests before grace period expires lastAttestation is updated. No penalty.
Agent attests after grace period expires lastAttestation is updated. Agent becomes compliant again immediately. No permanent penalty.
Agent is suspended while attesting Transaction reverts with "Agent not active". Wait for reactivation.
Relayer is temporarily unavailable SDK raises an exception. Retry after delay.
Multiple attestations in the same period Each attestation updates lastAttestation. No harm in attesting more frequently than required.
Agent's Haftungsperson changes Not supported on-chain. Register a new agent if the responsible party changes.