agentsclimarketplace

Human oversight design

Skill obielin/responsible-ai-skills/skills/human-oversight-design

Skills framework for coding agents that enforces responsible AI practices — bias assessment, fairness testing, explainability, governance documentation, and alignment review. Auto-activates when building AI systems.

Install
npx -y skills add obielin/responsible-ai-skills --skill human-oversight-design

Assembled from the repository path, not quoted from the project. Check it against their README if it does not work.

One thing to look at

  • 2 stars2 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.

What its author says it does

Copied from the file, not written here

Use when designing autonomous AI agents, agentic pipelines, or any system that takes actions without direct user instruction for each step. Must be read before writing any agent orchestration code.

SKILL.md

9.1 KB, as published. Nobody here has run it

Human Oversight Design

Autonomous AI agents that act without meaningful human control are a governance failure waiting to happen. This skill teaches you to design oversight into the system architecture — not bolt it on afterwards.

The Oversight Spectrum

Before writing any agent code, decide where your system sits:

Full Automation          Supervised Automation       Human-Led + AI-Assisted
─────────────────────────────────────────────────────────────────────────
AI decides & acts        AI decides, human approves  Human decides, AI informs
     │                          │                              │
High risk                   Medium risk                    Low risk
Requires audit trail    Requires override mechanism    Requires transparency

Rule: Systems affecting citizens, finances, health, or legal status must sit at "Supervised Automation" or further right. Argue in writing if you believe otherwise.


Step 1: Map Every Action to a Control Level

For every action your agent can take, assign a control level before implementation:

# Define your action registry with explicit oversight requirements
ACTION_REGISTRY = {
    # (action_name): (control_level, rationale)
    'read_database':          ('autonomous',  'Read-only, no external effect'),
    'generate_draft_email':   ('autonomous',  'Draft only, not sent'),
    'search_web':             ('autonomous',  'Read-only, no external effect'),
    'send_email':             ('supervised',  'External communication, irreversible'),
    'write_file':             ('supervised',  'Modifies state, potentially irreversible'),
    'delete_record':          ('supervised',  'Irreversible'),
    'submit_form':            ('supervised',  'External action with consequences'),
    'make_payment':           ('supervised',  'Financial transaction'),
    'update_citizen_record':  ('supervised',  'Affects individual entitlements'),
    'escalate_to_authority':  ('supervised',  'Triggers further action'),
    'take_legal_action':      ('blocked',     'Must not be automated'),
}

CONTROL_LEVELS = {
    'autonomous':  'Agent executes without approval',
    'supervised':  'Agent proposes, human must approve before execution',
    'blocked':     'Agent must not perform this action under any circumstances',
}

Step 2: Implement the Approval Gate

Every supervised action MUST pass through a gate:

from typing import Callable, Any
import logging

logger = logging.getLogger(__name__)

class OversightGate:
    """
    Enforces human approval for supervised actions.
    
    In production: integrates with your notification/approval system.
    In testing: can be configured to auto-approve or auto-reject.
    """
    
    def __init__(self, approval_fn: Callable, timeout_seconds: int = 3600):
        self.approval_fn = approval_fn
        self.timeout_seconds = timeout_seconds
    
    def request_approval(
        self,
        action: str,
        parameters: dict,
        agent_reasoning: str,
        risk_level: str = 'medium',
    ) -> bool:
        """
        Request human approval for a supervised action.
        
        Returns True if approved, False if rejected or timed out.
        Logs all decisions to audit trail.
        """
        request = {
            'action': action,
            'parameters': parameters,
            'agent_reasoning': agent_reasoning,
            'risk_level': risk_level,
            'requested_at': datetime.now(timezone.utc).isoformat(),
        }
        
        logger.info(f"OVERSIGHT_REQUEST: {json.dumps(request)}")
        
        approved = self.approval_fn(request, timeout=self.timeout_seconds)
        
        log_entry = {**request, 'approved': approved, 'decided_at': datetime.now(timezone.utc).isoformat()}
        logger.info(f"OVERSIGHT_DECISION: {json.dumps(log_entry)}")
        
        return approved
    
    def is_blocked(self, action: str) -> bool:
        level = ACTION_REGISTRY.get(action, ('supervised', 'unknown'))[0]
        return level == 'blocked'
    
    def requires_approval(self, action: str) -> bool:
        level = ACTION_REGISTRY.get(action, ('supervised', 'unknown'))[0]
        return level == 'supervised'


def execute_with_oversight(
    gate: OversightGate,
    action: str,
    parameters: dict,
    action_fn: Callable,
    agent_reasoning: str,
) -> Any:
    """
    Execute an agent action with appropriate oversight controls.
    
    This is the ONLY way agents should execute actions.
    Do not bypass this function.
    """
    if gate.is_blocked(action):
        raise PermissionError(
            f"Action '{action}' is blocked. Agents must not perform this action. "
            f"Escalate to a human operator."
        )
    
    if gate.requires_approval(action):
        approved = gate.request_approval(
            action=action,
            parameters=parameters,
            agent_reasoning=agent_reasoning,
        )
        if not approved:
            logger.warning(f"OVERSIGHT_REJECTED: action={action}")
            return None  # agent must handle rejection gracefully
    
    # Execute and log
    logger.info(f"AGENT_ACTION: {action} with params {parameters}")
    result = action_fn(**parameters)
    logger.info(f"AGENT_RESULT: {action} completed")
    return result

Step 3: Design for Corrigibility

Your agent must be stoppable at any point:

import threading

class AgentController:
    """Controls agent execution with pause and stop capability."""
    
    def __init__(self):
        self._stop_event = threading.Event()
        self._pause_event = threading.Event()
        self._pause_event.set()  # start unpaused
    
    def stop(self) -> None:
        """Immediately stop the agent after current step completes."""
        self._stop_event.set()
        logger.warning("AGENT_STOP_REQUESTED")
    
    def pause(self) -> None:
        """Pause the agent until resumed."""
        self._pause_event.clear()
        logger.info("AGENT_PAUSED")
    
    def resume(self) -> None:
        self._pause_event.set()
        logger.info("AGENT_RESUMED")
    
    def should_stop(self) -> bool:
        return self._stop_event.is_set()
    
    def check_pause(self) -> None:
        """Call this between every agent step. Blocks if paused."""
        self._pause_event.wait()  # blocks until resumed
    
    def run_step(self, step_fn: Callable) -> Any:
        """Execute one agent step with stop/pause checking."""
        if self.should_stop():
            raise AgentStoppedException("Agent was stopped by operator.")
        self.check_pause()
        return step_fn()

Step 4: Audit Trail — Every Action, Every Decision

class AgentAuditLog:
    """Immutable audit log for all agent actions and decisions."""
    
    def log_step(
        self,
        step_id: str,
        action: str,
        reasoning: str,
        inputs: dict,
        outputs: Any,
        human_approved: bool,
        approver: str | None = None,
    ) -> None:
        entry = {
            'step_id': step_id,
            'timestamp': datetime.now(timezone.utc).isoformat(),
            'action': action,
            'reasoning': reasoning,
            'inputs_summary': str(inputs)[:500],
            'outputs_summary': str(outputs)[:500],
            'human_approved': human_approved,
            'approver': approver,
        }
        # Write to append-only log — never delete entries
        with open('agent_audit.jsonl', 'a') as f:
            f.write(json.dumps(entry) + '\n')

Step 5: Override Rate Monitoring

Track how often humans override or reject agent proposals. A very low override rate may indicate rubber-stamping (automation bias), not good performance:

def compute_override_rate(audit_log_path: str, window_days: int = 30) -> float:
    """Compute the human override rate over the last N days."""
    ...
    # Alert if override rate drops below 5% for supervised actions
    # This may indicate humans are not exercising meaningful oversight
    if override_rate < 0.05:
        logger.warning(
            f"OVERSIGHT_ALERT: Override rate is {override_rate:.1%} — "
            f"possible automation bias. Review oversight process."
        )
    return override_rate

Completion Checklist

  • All agent actions classified in ACTION_REGISTRY with control level and rationale
  • OversightGate implemented for all supervised actions
  • Agent corrigibility implemented (stop/pause/resume)
  • Audit log captures every step, decision, and human approval
  • Override rate monitoring set up
  • System prompt or agent instructions explicitly state agent's boundaries
  • Tested: agent stops correctly when stop signal received
  • Tested: agent requests approval before executing supervised actions

Proceed to governance-documentation before deploying this system.

Keep looking

Skills are one crate of 328,083. Ordering is by how many stacks a row turns up in, so the top of any crate is what has actually been picked rather than what has the most stars.