Skip to main content

Anthropic Skills / Claude tool_use

Enact workflows are the governed implementation of Anthropic skills. The mapping is 1:1:
Anthropic SkillEnact Equivalent
Named, callable Python functionEnact Workflow
Input parameterspayload dict
OutputActionResult list
(no governance)Policy check + signed receipt + rollback
Instead of Claude calling your skill directly:
# Without Enact — Claude calls skill directly
tools = [{"name": "create_pr", "description": "..."}]
Register enact.run as the tool:
# With Enact — Claude calls enact.run, governance happens automatically
tools = [
    {
        "name": "enact_run",
        "description": "Run a governed agent workflow",
        "input_schema": {
            "type": "object",
            "properties": {
                "workflow": {"type": "string"},
                "payload": {"type": "object"},
            },
            "required": ["workflow", "payload"],
        },
    }
]

# When Claude calls the tool:
def handle_tool_call(tool_input):
    result, receipt = enact.run(
        workflow=tool_input["workflow"],
        user_email="agent@company.com",
        payload=tool_input["payload"],
    )
    return result
Claude can’t tell the difference. You added a governance layer without changing Claude’s behavior.

MCP (Model Context Protocol)

Anthropic’s Model Context Protocol is the open standard for connecting AI models to tools and data sources. Each Enact workflow maps to one MCP tool.
# In your MCP server — register enact.run as an MCP tool
@mcp_server.tool()
def run_workflow(workflow: str, payload: dict) -> dict:
    """Run a governed Enact workflow with policy enforcement and audit trail."""
    result, receipt = enact.run(
        workflow=workflow,
        user_email="agent@company.com",
        payload=payload,
    )
    return {"decision": result.decision, "run_id": receipt.run_id}
Every MCP tool call now gets a signed receipt. Every block gets logged. Every run is rollback-able.

LangChain

from langchain.tools import tool

@tool
def run_enact_workflow(workflow: str, payload: str) -> str:
    """Run a governed workflow. payload is a JSON string."""
    import json
    result, receipt = enact.run(
        workflow=workflow,
        user_email="agent@company.com",
        payload=json.loads(payload),
    )
    return f"Decision: {result.decision}. Run ID: {receipt.run_id}"

CrewAI

from crewai import Tool

enact_tool = Tool(
    name="run_workflow",
    description="Run a governed Enact workflow",
    func=lambda workflow, payload: enact.run(workflow=workflow, user_email="agent@company.com", payload=payload),
)

OpenAI function_calling

tools = [
    {
        "type": "function",
        "function": {
            "name": "run_workflow",
            "description": "Run a governed workflow with policy enforcement",
            "parameters": {
                "type": "object",
                "properties": {
                    "workflow": {"type": "string"},
                    "payload": {"type": "object"},
                },
                "required": ["workflow", "payload"],
            },
        },
    }
]

Semantic Kernel

An Enact workflow is a Semantic Kernel skill, hardened:
from semantic_kernel.skill_definition import sk_function

class EnactSkills:
    @sk_function(description="Run a governed Enact workflow")
    def run_workflow(self, workflow: str, payload: str) -> str:
        import json
        result, receipt = enact.run(
            workflow=workflow,
            user_email="agent@company.com",
            payload=json.loads(payload),
        )
        return result.decision

Summary

FrameworkHow to integrate
Anthropic tool_useRegister enact.run as a tool in your tools list
MCPDefine run_workflow as an MCP tool in your server
LangChainWrap with @tool decorator
CrewAIPass as a Tool object
OpenAI function_callingDefine in tools array
Semantic KernelWrap in a skill class with @sk_function
In every case: your agent’s prompting and reasoning stay exactly as-is. You’re adding a governance layer between intent and execution.