{"id":5181,"date":"2026-03-13T04:04:33","date_gmt":"2026-03-13T11:04:33","guid":{"rendered":"https:\/\/devblogs.microsoft.com\/semantic-kernel\/?p=5181"},"modified":"2026-03-13T04:04:33","modified_gmt":"2026-03-13T11:04:33","slug":"whats-new-in-agent-skills-code-skills-script-execution-and-approval-for-python","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/agent-framework\/whats-new-in-agent-skills-code-skills-script-execution-and-approval-for-python\/","title":{"rendered":"What&#8217;s New in Agent Skills: Code Skills, Script Execution, and Approval for Python"},"content":{"rendered":"<h1>Code-Defined Skills, Script Execution, and Approval for Agent Skills in Python<\/h1>\n<p>When we <a href=\"https:\/\/devblogs.microsoft.com\/semantic-kernel\/give-your-agents-domain-expertise-with-agent-skills-in-microsoft-agent-framework\/\">introduced Agent Skills<\/a> for Microsoft Agent Framework, you could package domain expertise as file-based skill directories and have agents discover and load them on demand. Now, the Python SDK takes skills further \u2014 you can define skills entirely in code, let agents execute scripts bundled with skills, and gate script execution behind human approval. These additions give you more flexibility in how you author skills, more power in what agents can do with them, and more control over when agents are allowed to act.<\/p>\n<h2>Code-Defined Skills<\/h2>\n<p>Until now, every skill started as a directory on the filesystem with a <code>SKILL.md<\/code> file. That works well for static, shareable knowledge packages, but not every skill fits that mold. Sometimes skill content comes from a database. Sometimes you want skill definitions to live alongside the application code that uses them. And sometimes a resource needs to execute logic at read time rather than serve static text.<\/p>\n<p>Code-defined skills address these scenarios. You create a <code>Skill<\/code> instance in Python with a name, description, and instruction content \u2014 no files required:<\/p>\n<pre><code class=\"language-python\">from textwrap import dedent\r\nfrom agent_framework import Skill, SkillResource, SkillsProvider\r\n\r\ncode_style_skill = Skill(\r\n    name=\"code-style\",\r\n    description=\"Coding style guidelines and conventions for the team\",\r\n    content=dedent(\"\"\"\\\r\n        Use this skill when answering questions about coding style,\r\n        conventions, or best practices for the team.\r\n    \"\"\"),\r\n    resources=[\r\n        SkillResource(\r\n            name=\"style-guide\",\r\n            content=dedent(\"\"\"\\\r\n                # Team Coding Style Guide\r\n                - Use 4-space indentation (no tabs)\r\n                - Maximum line length: 120 characters\r\n                - Use type annotations on all public functions\r\n            \"\"\"),\r\n        ),\r\n    ],\r\n)\r\n\r\nskills_provider = SkillsProvider(skills=[code_style_skill])\r\n<\/code><\/pre>\n<p>The agent uses code-defined skills exactly like file-based ones \u2014 calling <code>load_skill<\/code> to retrieve instructions and <code>read_skill_resource<\/code> to fetch resources. From the agent&#8217;s perspective, there&#8217;s no difference.<\/p>\n<h3>Dynamic Resources<\/h3>\n<p>Static content is useful, but sometimes you need resources that return fresh data each time they&#8217;re read. The <code>@skill.resource<\/code> decorator registers a function as a resource. Both sync and async functions are supported:<\/p>\n<pre><code class=\"language-python\">import os\r\nfrom agent_framework import Skill\r\n\r\nproject_info_skill = Skill(\r\n    name=\"project-info\",\r\n    description=\"Project status and configuration information\",\r\n    content=\"Use this skill for questions about the current project.\",\r\n)\r\n\r\n@project_info_skill.resource\r\ndef environment() -&gt; Any:\r\n    \"\"\"Get current environment configuration.\"\"\"\r\n    env = os.environ.get(\"APP_ENV\", \"development\")\r\n    region = os.environ.get(\"APP_REGION\", \"us-east-1\")\r\n    return f\"Environment: {env}, Region: {region}\"\r\n\r\n@project_info_skill.resource(name=\"team-roster\", description=\"Current team members\")\r\ndef get_team_roster() -&gt; Any:\r\n    \"\"\"Return the team roster.\"\"\"\r\n    return \"Alice Chen (Tech Lead), Bob Smith (Backend Engineer)\"\r\n<\/code><\/pre>\n<p>When the decorator is used without arguments (<code>@skill.resource<\/code>), the function name becomes the resource name and the docstring becomes the description. Use <code>@skill.resource(name=\"...\", description=\"...\")<\/code> to set them explicitly. The function is called each time the agent reads the resource, so it can pull up-to-date data from databases, APIs, or environment variables.<\/p>\n<h3>Code-Defined Scripts<\/h3>\n<p>Use the <code>@skill.script<\/code> decorator to register a function as an executable script on a skill. Code-defined scripts run <strong>in-process<\/strong> as direct function calls:<\/p>\n<pre><code class=\"language-python\">from agent_framework import Skill\r\n\r\nunit_converter_skill = Skill(\r\n    name=\"unit-converter\",\r\n    description=\"Convert between common units using a conversion factor\",\r\n    content=\"Use the convert script to perform unit conversions.\",\r\n)\r\n\r\n@unit_converter_skill.script(name=\"convert\", description=\"Convert a value: result = value \u00d7 factor\")\r\ndef convert_units(value: float, factor: float) -&gt; str:\r\n    \"\"\"Convert a value using a multiplication factor.\"\"\"\r\n    import json\r\n    result = round(value * factor, 4)\r\n    return json.dumps({\"value\": value, \"factor\": factor, \"result\": result})\r\n<\/code><\/pre>\n<p>A JSON Schema is automatically created from the function&#8217;s typed parameters and presented to the agent, so it knows what arguments the script expects and provides them accordingly when calling <code>run_skill_script<\/code>.<\/p>\n<h3>Combining File-Based and Code-Defined Skills<\/h3>\n<p>You can mix both approaches in a single <code>SkillsProvider<\/code>. Pass <code>skill_paths<\/code> for file-based skills and <code>skills<\/code> for code-defined ones. If a code-defined skill shares a name with a file-based skill, the file-based version takes precedence:<\/p>\n<pre><code class=\"language-python\">from pathlib import Path\r\nfrom agent_framework import Skill, SkillsProvider\r\n\r\nmy_skill = Skill(\r\n    name=\"my-code-skill\",\r\n    description=\"A code-defined skill\",\r\n    content=\"Instructions for the skill.\",\r\n)\r\n\r\nskills_provider = SkillsProvider(\r\n    skill_paths=Path(__file__).parent \/ \"skills\",\r\n    skills=[my_skill],\r\n)\r\n<\/code><\/pre>\n<h2>Script Execution<\/h2>\n<p>Skills can include executable scripts that the agent runs via the <code>run_skill_script<\/code> tool. How a script runs depends on how it was defined:<\/p>\n<ul>\n<li><strong>Code-defined scripts<\/strong> (registered via <code>@skill.script<\/code>) run in-process as direct function calls. No runner is needed.<\/li>\n<li><strong>File-based scripts<\/strong> (<code>.py<\/code> files discovered in skill directories) require a <code>SkillScriptRunner<\/code> \u2014 any callable matching <code>(skill, script, args) -&gt; Any<\/code> \u2014 that you provide to control how the script is executed.<\/li>\n<\/ul>\n<p>To enable execution of file-based scripts, pass a <code>script_runner<\/code> to <code>SkillsProvider<\/code>:<\/p>\n<pre><code class=\"language-python\">from pathlib import Path\r\nfrom agent_framework import Skill, SkillScript, SkillsProvider\r\n\r\ndef my_runner(skill: Skill, script: SkillScript, args: dict | None = None) -&gt; str:\r\n    \"\"\"Run a file-based script as a subprocess.\"\"\"\r\n    import subprocess, sys\r\n    cmd = [sys.executable, str(Path(skill.path) \/ script.path)]\r\n    if args:\r\n        for key, value in args.items():\r\n            if value is not None:\r\n                cmd.extend([f\"--{key}\", str(value)])\r\n    # ... Execute cmd in a sandboxed subprocess and return stdout\r\n    return result.stdout.strip()\r\n\r\nskills_provider = SkillsProvider(\r\n    skill_paths=Path(__file__).parent \/ \"skills\",\r\n    script_runner=my_runner,\r\n)\r\n<\/code><\/pre>\n<p><div class=\"alert alert-danger\">This runner is provided for <strong>demonstration purposes only<\/strong>. For production use, implement proper sandboxing, resource limits, input validation, and structured logging.<\/div><\/p>\n<p>The runner receives the resolved <code>Skill<\/code>, <code>SkillScript<\/code>, and an optional <code>args<\/code> dictionary. You control the execution environment \u2014 how scripts are launched, what permissions they have, and how their output is captured.<\/p>\n<h2>Script Approval<\/h2>\n<p>When agents can execute scripts, you need a way to keep a human in the loop for sensitive operations. Setting <code>require_script_approval=True<\/code> on <code>SkillsProvider<\/code> gates all script execution behind human approval. Instead of executing immediately, the agent pauses and returns approval requests that your application handles:<\/p>\n<pre><code class=\"language-python\">from agent_framework import Agent, Skill, SkillsProvider\r\n\r\n# Create provider with approval enabled\r\nskills_provider = SkillsProvider(\r\n    skills=[my_skill],\r\n    require_script_approval=True,\r\n)\r\n\r\n# ... Create an agent with skills_provider as a context provider and start a session\r\nresult = await agent.run(\"Deploy version 2.5.0 to production\", session=session)\r\n\r\n# Handle approval requests\r\nwhile result.user_input_requests:\r\n    for request in result.user_input_requests:\r\n        print(f\"Script: {request.function_call.name}\")\r\n        print(f\"Args: {request.function_call.arguments}\")\r\n\r\n        approval = request.to_function_approval_response(approved=True)\r\n        result = await agent.run(approval, session=session)\r\n<\/code><\/pre>\n<p>When a script is rejected (<code>approved=False<\/code>), the agent is informed that the user declined and can respond accordingly \u2014 explaining the limitation or suggesting an alternative approach.<\/p>\n<p>This pattern gives you the benefits of agent-driven script execution while maintaining the oversight that enterprise environments require.<\/p>\n<h2>Use Cases<\/h2>\n<h3>Data Validation Pipelines<\/h3>\n<p>Package your organization&#8217;s data quality rules as a skill with validation scripts. When an analyst asks the agent to check a dataset, it loads the skill, runs the validation script against the data, and reports results \u2014 all following the same rules every time. With approval enabled, a data steward can review each validation before it executes.<\/p>\n<h3>DevOps Runbooks<\/h3>\n<p>Turn your team&#8217;s operational procedures into skills with executable scripts for common tasks like log retrieval, health checks, or configuration changes. The agent loads the right runbook based on the issue, and the approval mechanism ensures that no deployment or infrastructure change happens without human sign-off.<\/p>\n<h3>Dynamic Knowledge from Internal Systems<\/h3>\n<p>Use code-defined skills with dynamic resources to surface live information from internal APIs, databases, or configuration systems. An HR agent can pull current policy details from a CMS at read time rather than relying on a static copy that might be stale.<\/p>\n<h2>Security Considerations<\/h2>\n<p>Script execution introduces additional responsibility. Agent Skills should be treated like any third-party code you bring into your project:<\/p>\n<ul>\n<li><strong>Review before use<\/strong> \u2014 Read all skill content and scripts before deploying. Verify that a script&#8217;s actual behavior matches its stated intent.<\/li>\n<li><strong>Sandbox execution<\/strong> \u2014 Run file-based scripts in isolated environments. Limit filesystem, network, and system-level access to only what the skill requires.<\/li>\n<li><strong>Use approval for sensitive operations<\/strong> \u2014 Enable <code>require_script_approval=True<\/code> for any skill that can produce side effects in production systems.<\/li>\n<li><strong>Audit and log<\/strong> \u2014 Record which skills are loaded, which scripts are executed, and what arguments are passed to maintain an audit trail.<\/li>\n<\/ul>\n<h2>Get Started<\/h2>\n<p>Code-defined skills, script execution, and script approval are available now in the Python <code>agent-framework<\/code> package. These features give you more ways to author skills, more capability within skills, and the safety controls needed for production deployments.<\/p>\n<p>To learn more and try it out:<\/p>\n<ul>\n<li>\ud83d\udcd6 <a href=\"https:\/\/learn.microsoft.com\/en-us\/agent-framework\/agents\/skills\">Agent Skills documentation on Microsoft Learn<\/a><\/li>\n<li>\ud83d\udcbb <a href=\"https:\/\/github.com\/microsoft\/agent-framework\/tree\/main\/python\/samples\/02-agents\/skills\">Python samples on GitHub<\/a><\/li>\n<li>\ud83d\udde3\ufe0f <a href=\"https:\/\/github.com\/microsoft\/agent-framework\/discussions\">Discussion boards<\/a> \u2014 share feedback, ask questions, and connect with the community<\/li>\n<\/ul>\n<p>We&#8217;re always interested in hearing from you. If you have feedback or questions, reach out to us on the <a href=\"https:\/\/github.com\/microsoft\/agent-framework\/discussions\">GitHub discussion boards<\/a>. And if you&#8217;ve been enjoying Agent Framework, give us a \u2b50 on <a href=\"https:\/\/github.com\/microsoft\/agent-framework\">GitHub<\/a>.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Code-Defined Skills, Script Execution, and Approval for Agent Skills in Python When we introduced Agent Skills for Microsoft Agent Framework, you could package domain expertise as file-based skill directories and have agents discover and load them on demand. Now, the Python SDK takes skills further \u2014 you can define skills entirely in code, let agents [&hellip;]<\/p>\n","protected":false},"author":157200,"featured_media":5169,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[143,145,27,34],"tags":[],"class_list":["post-5181","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-agent-framework","category-agent-skills","category-agents","category-python-2"],"acf":[],"blog_post_summary":"<p>Code-Defined Skills, Script Execution, and Approval for Agent Skills in Python When we introduced Agent Skills for Microsoft Agent Framework, you could package domain expertise as file-based skill directories and have agents discover and load them on demand. Now, the Python SDK takes skills further \u2014 you can define skills entirely in code, let agents [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/agent-framework\/wp-json\/wp\/v2\/posts\/5181","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/agent-framework\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/agent-framework\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/agent-framework\/wp-json\/wp\/v2\/users\/157200"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/agent-framework\/wp-json\/wp\/v2\/comments?post=5181"}],"version-history":[{"count":1,"href":"https:\/\/devblogs.microsoft.com\/agent-framework\/wp-json\/wp\/v2\/posts\/5181\/revisions"}],"predecessor-version":[{"id":5200,"href":"https:\/\/devblogs.microsoft.com\/agent-framework\/wp-json\/wp\/v2\/posts\/5181\/revisions\/5200"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/agent-framework\/wp-json\/wp\/v2\/media\/5169"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/agent-framework\/wp-json\/wp\/v2\/media?parent=5181"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/agent-framework\/wp-json\/wp\/v2\/categories?post=5181"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/agent-framework\/wp-json\/wp\/v2\/tags?post=5181"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}