Skip to main content

Autarkia

Tool governance for AI agents
面向 AI Agent 的工具治理层:注册表 · 显式风险分级 · 角色策略 · 可见性过滤 · 执行前拦截

PyPI Python CI License: MIT

简体中文 · English


中文

大多数 agent 框架回答的是怎么调工具。这个库回答跑久了才会冒出来的那个问题:谁能调、拦在哪、失败了算谁的。

它来自一个单机长期运行的 agent 运行时:20+ 领域、约 90 个工具,按角色隔离,权限校验发生在代码里而不是提示词里。

  • 注册表:工具实例、运行时启用/禁用、稳定的 OpenAI function-calling schema(输出字节稳定,避免每次请求都让 prompt cache 失效)。
  • 显式风险分级:每个工具必须声明风险等级(read / write / external_write / device_read / device_control / sensitive)。没声明就等于不存在——不会出现在检索里,也不会被模型看到。风险从不推断。
  • 角色策略:按角色(scope)配置 resident / on_demand / disabled,外加首轮关键词路由。没被授予的工具,看不见、搜不到、也调不动。
  • 可见性过滤:按人设的 allow/deny(按名字或 category),叠加 mode 与 sensitive-mode 覆盖。
  • 执行边界:用本次请求自己的授权快照校验、校验参数、每次调用复制一份工具实例(并发角色之间不串状态)。

除 pydantic 外零运行时依赖,不绑定框架:工具是普通类,注册表是普通对象,导出的 schema 任何支持 function calling 的 API 都能用。

安装

pip install autarkia

快速开始

完整可运行版本:examples/minimal.py(无网络、无 API key)。

from pydantic import BaseModel
from autarkia import BaseTool, ToolCatalog, ToolDeclaration, ToolRegistry

class EchoArgs(BaseModel):
    text: str

class EchoTool(BaseTool):
    name = "echo"
    description = "Echo the given text back."
    args_schema = EchoArgs

    async def _run(self, text: str) -> str:
        return text

# 声明它是什么:未声明 = 不可见
catalog = ToolCatalog()
catalog.declare("echo", ToolDeclaration(
    domain="utility", risk_level="read", load_policy="on_demand",
))

registry = ToolRegistry(catalog=catalog)
registry.register(EchoTool())
print(registry.get_openai_tools())        # 稳定、可缓存

角色策略与可见性过滤:

from autarkia import RolePolicyResolver, filter_tool_names

profiles = {
    "defaults": {"on_demand": ["domain:*"]},
    "roles": {"librarian": {"resident": ["echo"], "disabled": ["domain:execution"]}},
    "modes": {},
    "routes": [{"keywords": ["repeat"], "tools": ["echo"]}],
}

resolver = RolePolicyResolver(profiles, catalog=catalog)
policy = resolver.resolve(scope="librarian")

visible = filter_tool_names(
    registry.get_active_tools(), policy=policy, tool_registry=registry,
)
picked = resolver.select("please repeat this", scope="librarian")

执行拦截(不需要把整个 runtime 对象塞进来):

import asyncio
from autarkia import execute_tool_call

result = asyncio.run(execute_tool_call(
    registry=registry,                 # 本次请求授权时用的那个注册表
    tool_name="echo",
    arguments={"text": "hi"},
    allowed_tool_names=visible,        # 空列表 = 什么都不许,安全默认
    user_id="user-1",
    context={"is_master": False},      # 额外上下文,最后合并、可覆盖派生值
))

三层分工(为什么不是一层)

层 回答的问题 数据来源
声明 ToolDeclaration 这个工具是什么(领域、标签、风险、加载策略) 每个工具的显式声明
角色策略 RoleToolPolicy 这个角色能不能调(粗粒度闸门:resident / on_demand / disabled) 注入的 profiles 映射
可见性 filter_tool_names 此刻要不要给模型看(人设 allow/deny、mode / sensitive 覆盖) 人设的 tool_access

一句话:角色策略决定“能不能调”,可见性决定“要不要露出来”,执行边界负责“真的调的时候再查一遍”。

风险分级与加载策略

风险:read → write → external_write → device_read → device_control → sensitive
加载:base(常驻) / on_demand(检索发现) / hidden(存在但不广播)

和主运行时的关系

Autarkia 本身不在 PyPI 上——它是一个单机运行时,不是 SaaS。这个包把那次实验里活下来的治理层单独发出来。

许可

MIT


English

Most agent frameworks answer how to call a tool. This library answers the question that shows up after your agent has been running for a while: who is allowed to call what, and what happens before it runs.

It comes from a self-hosted agent runtime that has run on a single machine for months: 20+ domains, around 90 tools, isolated per role, with permission checks in code — not prompt promises.

  • Registry — tool instances, runtime enable/disable, and byte-stable OpenAI function-calling schemas (so API-side prompt caches keep hitting).
  • Declared risk levels — every tool carries an explicit risk class (read, write, external_write, device_read, device_control, sensitive). If you forgot to declare one, it simply does not exist for discovery: risk is never inferred.
  • Role policies — resident / on-demand / disabled per role, plus keyword routing for the first turn. A role that was never granted a tool cannot see it, search it, or call it.
  • Visibility rules — persona-level allow/deny by name or category, with mode and sensitive-mode overlays.
  • Execution guard — authorization against the request's own snapshot, argument validation, and per-call context isolation (no shared mutable tool state across concurrent roles).

Zero runtime dependencies beyond pydantic. No framework lock-in: tools are plain classes, the registry is a plain object, and the exported schema works with any API that speaks function calling.

Install

pip install autarkia

Quick start

Runnable end to end: examples/minimal.py — no network, no API key.

from pydantic import BaseModel
from autarkia import BaseTool, ToolCatalog, ToolDeclaration, ToolRegistry

class EchoArgs(BaseModel):
    text: str

class EchoTool(BaseTool):
    name = "echo"
    description = "Echo the given text back."
    args_schema = EchoArgs

    async def _run(self, text: str) -> str:
        return text

catalog = ToolCatalog()
catalog.declare("echo", ToolDeclaration(
    domain="utility", risk_level="read", load_policy="on_demand",
))

registry = ToolRegistry(catalog=catalog)
registry.register(EchoTool())
print(registry.get_openai_tools())        # stable, cacheable

Role policy and visibility:

from autarkia import RolePolicyResolver, filter_tool_names

profiles = {
    "defaults": {"on_demand": ["domain:*"]},
    "roles": {"librarian": {"resident": ["echo"], "disabled": ["domain:execution"]}},
    "modes": {},
    "routes": [{"keywords": ["repeat"], "tools": ["echo"]}],
}

resolver = RolePolicyResolver(profiles, catalog=catalog)
policy = resolver.resolve(scope="librarian")

visible = filter_tool_names(
    registry.get_active_tools(), policy=policy, tool_registry=registry,
)
picked = resolver.select("please repeat this", scope="librarian")

The guard takes the registry directly — no runtime object required:

import asyncio
from autarkia import execute_tool_call

result = asyncio.run(execute_tool_call(
    registry=registry,                 # the registry this request was authorized against
    tool_name="echo",
    arguments={"text": "hi"},
    allowed_tool_names=visible,        # empty means nothing is allowed — a safe default
    user_id="user-1",
    context={"is_master": False},      # merged last; may override derived values
))

Three layers, not one

Layer Question it answers Where the data comes from
ToolDeclaration What is this tool (domain, tags, risk, load policy) explicit declaration per tool
RoleToolPolicy May this role call it (coarse gate: resident / on_demand / disabled) injected profiles mapping
filter_tool_names Should the model see it right now (persona allow/deny, mode / sensitive overlays) the persona's tool_access block

In one line: role policy decides whether a tool may run, visibility decides whether it is shown, and the execution guard re-checks at call time.

Risk levels and load policies

risk: read → write → external_write → device_read → device_control → sensitive
load: base (always offered) / on_demand (found via search) / hidden (exists, never advertised)

The bigger picture

Autarkia itself is not on PyPI — it is a single-machine runtime, not a SaaS. This package ships the governance layer that survived that experiment, because it turned out to be the part other projects kept asking for.

License

MIT

Metadata

Release files for Autarkia 0.2.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for Autarkia 0.2.0
File Size Uploaded Provenance
autarkia-0.2.0.tar.gz 23.8 kB Without provenance Details

Built distribution (wheel)

Table of built distributions (wheels) for Autarkia 0.2.0
File Interpreter ABI Platform
autarkia-0.2.0-py3-none-any.whl Python 3 none any Details

Total release size: 44.4 kB

Release files / autarkia-0.2.0.tar.gz

Download URL autarkia-0.2.0.tar.gz
Size 23.8 kB
Tags Source
SHA-256 checksum
How to use checksums
bdeab23d04b56b68388c44ccab8aa3f2e10a866d6834f697d0ff6809abf8faa5
BLAKE2b-256 checksum
How to use checksums
9e9b2b0bc65d2835b6fccb7489f15ddab0cbdb6b667d1835dc11113393da8521
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.10.11

Release files / autarkia-0.2.0-py3-none-any.whl

Download URL autarkia-0.2.0-py3-none-any.whl
Size 20.7 kB
Tags Python 3
SHA-256 checksum
How to use checksums
f68ab0818b87f8ea3d2a2bc8afece1720c3304f871d0f2b96aadf8a858a04001
BLAKE2b-256 checksum
How to use checksums
7ca25a56262be86513e5771811a0c294e885f831c2c5061f3e3784c8e78d054b
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.10.11

Security for Autarkia 0.2.0

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page