Built-in tools for the Microsoft Agent Framework (local shell, and more).
Project description
agent-framework-tools
Alpha built-in tools for the Microsoft Agent Framework. A home for first-party
Python tools that plug into any chat client's shell / function surface. The
first tool is LocalShellTool.
Installation
pip install agent-framework-tools --pre
LocalShellTool quick start
import asyncio
from agent_framework import Agent
from agent_framework.openai import OpenAIChatClient
from agent_framework_tools.shell import LocalShellTool
async def main() -> None:
client = OpenAIChatClient(model="gpt-5.4-nano")
async with LocalShellTool() as shell:
agent = Agent(
client=client,
instructions="You are a helpful assistant that can run shell commands.",
tools=[client.get_shell_tool(func=shell.as_function())],
)
result = await agent.run("Print the current working directory.")
print(result.text)
asyncio.run(main())
Modes
- Persistent (default): a single long-lived shell session.
cd,export, and shell functions persist across tool invocations. - Stateless (
mode="stateless"): each command runs in a fresh subprocess.
Safety
LocalShellToolis not a sandbox. It runs commands directly on the host with the agent process's privileges. The actual security boundary is approval-in-the-loop. For untrusted input use a sandboxed executor — seeagent-framework-hyperlight.
Defenses (in priority order):
- Approval-in-the-loop — every command surfaces as a
user_input_request; nothing runs without consent. Disabling this requiresacknowledge_unsafe=True. - Process-tree termination on timeout via
psutil, so child processes (make, watchers, network tools) cannot survive the timeout. - Output truncation to 64 KiB (head + tail with marker).
- Audit hook (
on_command=…) for SIEM / append-only logs. - Optional command-pattern filter via
ShellPolicy(denylist=[...], allowlist=[...]). Empty by default. This is a UX pre-filter, not a security boundary — operators are expected to supply patterns that match their workload (and they can be defeated by trivial obfuscation such as\rm -rf /,${RM:=rm} -rf /,python -c "…", encoded payloads, or PowerShell-native equivalents). Real isolation comes from approval gating and the sandbox tier (DockerShellTool). Seetests/test_security.pyfor the documented residual risk surface.
Override with ShellPolicy:
from agent_framework_tools.shell import LocalShellTool, ShellPolicy
shell = LocalShellTool(
policy=ShellPolicy(allowlist=[r"^ls\b", r"^cat\b", r"^git status$"]),
approval_mode="never_require",
acknowledge_unsafe=True, # required to bypass approval
)
Cross-OS
- Windows:
pwsh -NoProfile -Command -(falls back topowershell.exe). - Linux / macOS:
/bin/bash --noprofile --norc(falls back to/bin/sh). - Override via the
shell=constructor argument or theAGENT_FRAMEWORK_SHELLenvironment variable.
ShellEnvironmentProvider — context provider
A model talking to a PowerShell session will sometimes default to bash
syntax (export FOO=bar, ls -la, > /dev/null) and vice versa.
ShellEnvironmentProvider is an AIContextProvider that probes the live
shell once per session — family, version, OS, working directory, and a
configurable list of CLI tools (git, node, python, docker by
default) — and injects a system-prompt block describing the shell idiom
to use and the available CLIs.
from agent_framework_tools.shell import (
LocalShellTool,
ShellEnvironmentProvider,
ShellEnvironmentProviderOptions,
)
shell = LocalShellTool()
provider = ShellEnvironmentProvider(
shell,
ShellEnvironmentProviderOptions(probe_tools=("git", "uv", "node")),
)
agent = Agent(
client=client,
tools=[client.get_shell_tool(func=shell.as_function())],
context_providers=[provider],
)
Probe failures from expected error types (timeouts, policy rejections,
spawn failures) are recorded as None fields in the snapshot rather
than raised; a missing CLI never fails the agent. A failed first probe
does not poison the cache — the next call retries.
DockerShellTool — sandboxed tier
When commands originate from untrusted input (e.g. the model is acting on
prompt-injected document content), prefer DockerShellTool. With the
default isolation flags and a trusted container runtime, the container
is the intended security boundary and approval gating becomes optional.
import asyncio
from agent_framework_tools.shell import DockerShellTool
async def main() -> None:
async with DockerShellTool(
image="mcr.microsoft.com/azurelinux/base/core:3.0",
approval_mode="never_require", # container is the boundary
) as shell:
result = await shell.run("uname -a && id")
print(result.stdout)
asyncio.run(main())
Defaults applied to every container:
--network none— no host or external network.--user 65534:65534— runs asnobody:nogroup.--read-onlyroot filesystem; only mounted host paths are writable.--cap-drop ALLand--security-opt no-new-privileges.--memory 512m,--pids-limit 256, ephemeraltmpfs /tmp.
To expose a host directory, pass host_workdir="/path" (mounted
read-only by default; mount_readonly=False to allow writes). Swap the
container runtime with docker_binary="podman".
Sandbox tiers at a glance
| Use case | Tool | Sandbox |
|---|---|---|
| Run code (untrusted) | HyperlightCodeActProvider.execute_code (agent-framework-hyperlight) |
Hyperlight WASM microVM |
| Run shell (untrusted) | DockerShellTool |
OCI container (network-off, non-root, capabilities dropped) |
| Run shell (trusted dev) | LocalShellTool |
Approval-in-the-loop |
Relationship to agent-framework-hyperlight
agent-framework-hyperlight is a code sandbox (a single WASM guest
loaded into a microVM, called via a hostcall ABI — there is no kernel,
userland, or shell binary inside). It is the right tier for executing
generated code. For sandboxing shell commands, the realistic tier is
OCI, which DockerShellTool provides.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file agent_framework_tools-1.0.0a260424.tar.gz.
File metadata
- Download URL: agent_framework_tools-1.0.0a260424.tar.gz
- Upload date:
- Size: 35.4 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.11.6 {"installer":{"name":"uv","version":"0.11.6","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":null,"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
8317713f6d5e8b52b79fcd5b0d66d287e22da3e581d7a0b113598583137de68d
|
|
| MD5 |
f51506aa7a34eed0313cc0535706093c
|
|
| BLAKE2b-256 |
67c7edd7d27af789e52dcf5757620715cf3923065f47912ce10ed6850d819f41
|
File details
Details for the file agent_framework_tools-1.0.0a260424-py3-none-any.whl.
File metadata
- Download URL: agent_framework_tools-1.0.0a260424-py3-none-any.whl
- Upload date:
- Size: 40.4 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.11.6 {"installer":{"name":"uv","version":"0.11.6","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":null,"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
a757e289e759bf08eb497503a1597a678afda8a16f0b42adab5f7e3c862d44f7
|
|
| MD5 |
99c5fbd2da065ec88cf086b40dce85b7
|
|
| BLAKE2b-256 |
77f88b475cfbce2602aa9184edba3824be741c07fd9536d662075c32fb271a66
|