Skill in 《Agent Tool Builder》

Skill Description

Define agent tools using the fail-closed design pattern — unified name, schema, security properties, and execution logic in one class, with three-layer execution (validate → permission → call). Framework-agnostic: works with hermes-agent, LangChain, or any Python agent framework.

Skill.md

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.
  2. Layered executionvalidate_semantics → check_permissions → _call are separate methods, so validation logic doesn't bleed into permission logic or business logic.
  3. 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.

FieldQuestionDefault
nameTool name (format: {service}_{action}_{resource}, e.g. stock_get_price)— required
descriptionOne-sentence description for the LLM: precisely match actual functionality — vague descriptions cause the agent to misuse the tool— required
Schema fieldsWhat parameters does the tool accept? (field name, type, description; add example in Field description)— required
is_read_onlyDoes this tool only read data, with no writes or side effects?False
is_destructiveDoes this tool perform irreversible operations (delete, overwrite)?False
is_concurrency_safeCan this tool run simultaneously with other tools?False
response_formatIs the return data for agent programmatic processing (JSON) or user display (Markdown)?Markdown by default
List tool?If returning multiple records, support pagination?Recommended for 50+ records
_validate_input_semanticsAny semantic issues to catch before execution? (e.g. too-short query, wrong format)Not needed
_check_permissionsAny permissions to check? (e.g. required env var, caller identity restriction)Not needed
_callWhat is the core execution logic of the tool?— 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

"""<tool_name>.py — <one-line description>"""

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


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

class <ToolName>Input(BaseModel):
    <field_name>: <type> = Field(description="<description>. e.g. '<example>'")
    # ... more fields


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

class <ToolName>Tool(AgentTool):
    # — identity —
    name: str = "<tool_name>"
    description: str = "<one-sentence description for the LLM>"
    args_schema = <ToolName>Input

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

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

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

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

Common security property patterns

Tool typeis_read_onlyis_destructiveis_concurrency_safe
Search / queryTrueFalseTrue
File readTrueFalseTrue
File write / modifyFalseFalseFalse
Delete operationFalseTrueFalse
API call (GET)TrueFalseTrue
API call (POST/DELETE)FalsedependsFalse
Database queryTrueFalseTrue
Database writeFalseFalseFalse

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
FormatWhen to use
JSONAgent needs to parse/filter the result programmatically
MarkdownResult 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 — Full AgentTool base class (pure Python, no framework dependency)

Install & Use

Install command

npx skills add simbajigege/book2skills/skills/agent-tool-builder
OR

Direct download

Related Skills

LangChain Tool Builder AI Skill

Build LangChain (Python) tools using Claude Code's fail-closed design pattern — unified name, schema, security, and execution in one class, with automatic three-layer execution.

Tool Permission System AI Skill

Design a configurable, layered permission/safety system for agent tools: one permission pipeline decides allow / ask / deny, rules layer across enterprise / user / project scopes.

Query Loop Implementation AI Skill

Implement a production-ready LLM query loop for AI applications: tool calls, structured tool_result passback, ReAct loop, max-turn exit, permission checks, timeout, and budget control.

Harness Step 1 — Create AGENTS.md AI Skill

Scan the project codebase and auto-generate AGENTS.md (agent orientation guide) and a complete docs/ knowledge base skeleton so Claude Code orients in 30 seconds in any new session.

Harness Step 2 — Fill docs/ Knowledge Base AI Skill

Deep-read project code and write hidden architectural knowledge, naming conventions, and tech decisions explicitly into docs/ files so the agent understands the project in any session.

Harness Step 3 — Session State Management AI Skill

Create init.sh (health check), tasks.json (structured task queue), and progress.md (session log) to solve Claude Code's amnesia problem across sessions.

Folded Memory Implementation Guide AI Skill

A developer implementation guide for building hierarchical (folded) memory into an Agent — three-layer architecture where recent turns stay detailed.

Compact Memory Implementation AI Skill

Developer guide for implementing compact memory in agents using the Anthropic API or Claude Agent SDK — trigger timing, fork compactor pattern, compact JSON schema design.

Compact with Memory AI Skill

Execute /compact correctly — generate high-quality conversation summaries preserving reasoning, decision context, and current state, while persisting institutional knowledge before compression.

Agent Memory Implementation AI Skill

Refactor a messy MEMORY.md into Claude Code's 2-layer memory architecture — keep the resident index lean, load topic files on demand, so the autoDream extraction agent deduplicates correctly.

Session Dream AI Skill

Manual memory distillation at session end — extract key decisions, failed paths, new findings, and current blockers from the current conversation and write them into MEMORY.md topic files.