AgentStack
Browse Sign in
Browse Why AgentStack Sell Docs
Sign in
SKILL verified MIT Self-run

Agent Tool Builder

skill-simbajigege-book2skills-agent-tool-builder · by simbajigege

Define agent tools using the fail-closed design pattern — unified name/schema/security/execution in one class, with three-layer execution (validate → permission → call). Use this skill whenever the user wants to define a new agent tool, add permission or validation logic to an existing tool, or asks about 'build a tool', '定义一个工具', 'create a tool for X', '工具定义'. Framework-agnostic: works with herm…

No reviews yet
0 installs
22 views
0.0% view→install

Install

$ agentstack add skill-simbajigege-book2skills-agent-tool-builder

✓ scanned · ✓ verified, works with Claude Code, Cursor, and more.

Security review

✓ Passed

No issues found. Passed automated security review. · v0.1.0 How review works →

  • Prompt-injection patterns
  • Secret / credential exfiltration
  • Dangerous shell & filesystem operations
  • Untrusted network calls
  • Known-malicious package signatures

What it can access

  • Network access No
  • Filesystem access No
  • Shell / process execution No
  • Environment & secrets No
  • Dynamic code execution No

From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.

View the full security report →

Verified badge

Passed review? Show it. Paste this badge into your README, it links to the public security report.

AgentStack Verified badge Links to your public security report.
[![AgentStack Verified](https://agentstack.voostack.com/badges/verified.svg)](https://agentstack.voostack.com/security/report/skill-simbajigege-book2skills-agent-tool-builder)

Reliability & compatibility

Security review passed
0 installs to date
no reviews yet
1mo ago

Declared compatibility

Claude CodeClaude Desktop

Compatibility is declared by the source manifest. End-to-end runtime verification is coming, see below.

Preview Execution monitoring

We're building live execution health for every listing: tool-call success rate, median latency, uptime, and last-checked timestamps, measured, not self-reported. It isn't live yet, so we don't show numbers we can't stand behind.

How agent discovery & health will work →
Are you the author of Agent Tool Builder? Claim this listing to set pricing, connect Stripe payouts, and keep 70% of every sale.
Sign up to claim

About

Agent Tool Builder

Helps define agent tools using the fail-closed design pattern: a unified class that co-locates identity, schema, security properties, and execution logic, with fail-closed defaults so new tools are safe by default.

Why this pattern matters

Three things that ad-hoc tool definitions lack:

  1. Fail-closed defaultsis_read_only, is_destructive, is_concurrency_safe all default to False.

A tool that forgets to declare its properties is conservatively treated as write-capable.

  1. Layered executionvalidate_semantics → check_permissions → _call are separate methods,

so validation logic doesn't bleed into permission logic or business logic.

  1. Self-contained definition — schema, description, security metadata, and execution all live

in one place. No separate middleware to wire up.


Workflow

Step 1 — Identify the target framework

Ask which agent framework the tool will be registered in (e.g. hermes-agent, LangChain, plain Python). This determines the import path and registration method, but the design principles are identical.

Check if agent_tool_base.py exists in the project's utils/tools directory. If not, copy it from references/agent_tool_base.py in this skill directory. Tell the user where it was placed.

Step 2 — Interview the user

Collect answers to these questions. Defaults are shown — skip questions where the default is clearly fine.

Naming convention: use {service}_{action}_{resource} format with a service prefix so the tool stays unambiguous when multiple tool sets are loaded simultaneously (e.g. stock_get_price, stock_list_symbols, stock_search_news). Start with a verb: get, list, search, create, delete.

| Field | Question | Default | |---|---|---| | name | 工具名(格式:{service}_{action}_{resource},例如 stock_get_price) | — required | | description | 给 LLM 看的一句话描述:精确匹配实际功能,不要模糊扩大,否则 agent 会在不该用的场景误调用 | — required | | Schema fields | 工具接受哪些参数?(字段名、类型、说明;在 Field description 里加 example) | — required | | is_read_only | 这个工具只读数据,不写入/不产生副作用吗? | False | | is_destructive | 这个工具会做不可逆操作(删除、覆盖)吗? | False | | is_concurrency_safe | 这个工具可以和其他工具同时运行吗? | False | | response_format | 返回数据是给 agent 程序化处理(JSON)还是给用户展示(Markdown)? | 视场景,默认 Markdown | | 是否列表工具 | 如果返回多条记录,要支持分页吗? | 超过 50 条建议加 | | _validate_input_semantics | 有没有需要在执行前拦截的语义问题?(如:参数太短、格式不对) | 不需要 | | _check_permissions | 有没有需要检查的权限?(如:需要某个 env var、调用方身份限制) | 不需要 | | _call | 工具的核心执行逻辑是什么? | — required |

You don't have to ask all questions upfront — infer reasonable answers from context. For example, a "search" or "get" tool is almost certainly is_read_only=True, is_concurrency_safe=True.

Step 3 — Generate the tool file

Create a .py file for the tool. Follow this field order:

1. imports
2. Input schema (Pydantic BaseModel)
3. Tool class:
   a. name, description, args_schema      — identity
   b. is_read_only, is_destructive, is_concurrency_safe, max_result_chars  — security metadata
   c. _validate_input_semantics()         — semantic validation (omit if unneeded)
   d. _check_permissions()               — permission check (omit if unneeded)
   e. _call()                            — actual logic

Suggest a file path consistent with the project's tool directory structure.

Step 4 — Show security property summary

After generating, print a one-line summary of the tool's security posture:

StockGetPriceTool: read_only=True  destructive=False  concurrency_safe=True  max_result=10K

Output template

""".py — """

from typing import Optional
from pydantic import BaseModel, Field
from base.utils.agent_tool_base import AgentTool

# ---------------------------------------------------------------------------
# Input schema
# ---------------------------------------------------------------------------

class Input(BaseModel):
    :  = Field(description=". e.g. ''")
    # ... more fields

# ---------------------------------------------------------------------------
# Tool class
# ---------------------------------------------------------------------------

class Tool(AgentTool):
    # — identity —
    name: str = ""
    description: str = ""
    args_schema = Input

    # — security metadata (fail-closed: only set True when verified) —
    is_read_only: bool = 
    is_destructive: bool = 
    is_concurrency_safe: bool = 
    max_result_chars: int = 10_000

    # — semantic validation (omit if no input constraints needed) —
    def _validate_input_semantics(self, , **kwargs) -> tuple[bool, Optional[str]]:
        if not :
            return False, ". Try "
        return True, None

    # — permission check (omit if no access control needed) —
    def _check_permissions(self, , **kwargs) -> tuple[bool, Optional[str]]:
        if not :
            return False, ". "
        return True, None

    # — core logic —
    def _call(self, , **kwargs) -> str:
        # ... implement tool logic here
        return result

Common security property patterns

| Tool type | isreadonly | isdestructive | isconcurrency_safe | |---|---|---|---| | 搜索 / 查询 | True | False | True | | 文件读取 | True | False | True | | 文件写入 / 修改 | False | False | False | | 删除操作 | False | True | False | | API 调用(GET) | True | False | True | | API 调用(POST/DELETE) | False | 视情况 | False | | 数据库查询 | True | False | True | | 数据库写入 | False | False | False |


Output design principles

Atomic tools — one tool, one responsibility

Keep each tool focused on a single operation. Let the agent compose multiple tools to complete complex tasks. A tool that does too much is harder for the agent to reuse and reason about.

Response format — JSON vs Markdown

| Format | When to use | |---|---| | JSON | Agent needs to parse/filter the result programmatically | | Markdown | Result will be shown directly to a user |

Support both when uncertain — accept an optional response_format: str = "markdown" parameter and branch in _call. For JSON output use json.dumps(data, ensure_ascii=False, indent=2).

Pagination for list tools

Any tool that can return more than ~50 records should support pagination:

return json.dumps({
    "items": [...],
    "total": 150,
    "count": 20,
    "offset": 0,
    "has_more": True,
    "next_offset": 20,
}, ensure_ascii=False, indent=2)

Add offset: int = Field(default=0, description="Pagination offset") and limit: int = Field(default=20, description="Max items to return") to the input schema.

Actionable error messages

Error strings must guide the agent toward a fix — not just describe the failure:

# Bad: agent is stuck
return False, "Query too short."

# Good: agent knows exactly what to try next
return False, "Query too short (got 2 chars, need >= 3). Provide a more specific search term."

Reference files

  • references/agent_tool_base.py — 完整的 AgentTool 基类(纯 Python,无框架依赖)

Source & license

This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.

Install and usage instructions live in the source repository linked above.

Reviews

No reviews yet, be the first.

Versions

  • v0.1.0 Imported from the upstream source.