---
name: tool-creator-e3c54c64e49c
description: >-
  A meta-skill for creating Python external tool modules for AnimaWorks.core/integrationsHandles integrations, get_credential, and permissions.
  Use when: core/integrationsWhen you need to add a new module, implement a Web API wrapper, or develop a custom tool called by animaworks-tool.
---


# tool-creator

## Overview

AnimaWorks tools are divided into three types:

| Type | Location | Discovery method |
|------|--------|----------|
| **Core tools** | `core/integrations/*.py` (files with the `_` prefix are excluded) | `discover_core_tools()` → `TOOL_MODULES` (package import) |
| **Shared tools** | `{data_dir}/common_tools/*.py` | `discover_common_tools()` |
| **Personal tools** | `{anima_dir}/tools/*.py` | `discover_personal_tools()` |

`{data_dir}` is usually `~/.animaworks/`.

- **Dispatch**: `ExternalToolDispatcher` has deprecated `_DISPATCH_TABLE` and standardized on `dispatch(name, args)` in each module (or a function with the same name as the schema) (`core/tooling/dispatch.py`).
- **Merging**: At startup, both `_discover_personal_tools()` and `refresh_tools` for `AgentCore` merge in the order **shared → personal**, with **personal tools overriding entries with the same name** (`{**common, **personal}`). The merged result is held in `_personal_tools` of `ExternalToolDispatcher` (the name is historical, but it **also includes shared tools**).
- **Core conflicts**: Files with the same name as core `TOOL_MODULES` are **skipped** when discovering shared and personal tools (warning log only).
- **Writing tool files**: When writing to `tools/*.py` via `write_memory_file`, the **tool_creation.personal** requirement of `permissions` (**`permissions.json` takes precedence**) must be met (`core/tooling/handler_memory.py`).

## Execution Path (How the LLM Calls It)

| Mode | Typical Path |
|--------|-----------|
| **A (LiteLLM, etc.)** | Integrated tool **`use_tool(tool_name, action, args)`** → module's `dispatch` (`core/tooling/handler.py`). Details are designed so that each tool's skill is read via **`read_memory_file`** (`USE_TOOL` of `core/tooling/schemas/skill.py`). |
| **S (Agent SDK)** | Via Claude Code's built-in **Bash** with `animaworks-tool <ツール> …`, or via MCP (only a curated subset is exposed to MCP; see "Adding Core Tools to the Repository" below). |
| **Anthropic fallback, etc.** | `include_use_tool=False` configuration may exist in `build_tool_list` → externally, this assumes **Bash + animaworks-tool** or skills. |

At startup, the merged map above is passed to `ToolHandler`, so common and personal tools placed **before process startup** are available from the beginning via `use_tool` / `ExternalToolDispatcher`. For **`.py` newly added during a session**, `use_tool` will not recognize the tool name unless a rescan is performed via `refresh_tools` (because the map is not updated).

## Procedure

### Step 1: Tool Design

1. Decide the tool name (module name) (snake_case, e.g., `my_api_tool`). This becomes the first argument of `animaworks-tool my_api_tool …`.
2. Decide the **actions** (subcommands). Schema names should generally follow **`{tool_name}_{action}`** (e.g., `myapi_query`). In `use_tool`, use `tool_name="myapi"`, `action="query"`.
3. Define parameters using JSON Schema (`input_schema` or `parameters`).

### Step 2: Creating the Module File

#### Single-Action Example

```python
from __future__ import annotations

import logging
from typing import Any

logger = logging.getLogger(__name__)


def get_tool_schemas() -> list[dict]:
    """ツールスキーマを返す。個人・共有ツールでは必須推奨（スキーマ読み込み・ログ用）。"""
    return [
        {
            "name": "my_tool_action",
            "description": "このツールが何をするかの説明",
            "input_schema": {
                "type": "object",
                "properties": {
                    "param1": {
                        "type": "string",
                        "description": "パラメータの説明",
                    },
                    "param2": {
                        "type": "integer",
                        "description": "オプションパラメータ",
                        "default": 10,
                    },
                },
                "required": ["param1"],
            },
        }
    ]


def dispatch(name: str, args: dict[str, Any]) -> Any:
    """スキーマ名に応じた処理を実行する（推奨）。"""
    args.pop("anima_dir", None)  # フレームワークから注入。必要なら Path(anima_dir) で利用
    if name == "my_tool_action":
        return _do_action(
            param1=args["param1"],
            param2=args.get("param2", 10),
        )
    raise ValueError(f"Unknown tool: {name}")


def _do_action(param1: str, param2: int = 10) -> dict[str, Any]:
    return {"result": f"Processed {param1} with {param2}"}
```

When calling from `animaworks-tool`, **`cli_main` must be implemented** afterward (see the "`cli_main`" section below).

#### Multiple Actions + Authentication (API Integration)

The resolution order for `get_credential(credential_name, tool_name, key_name="api_key", env_var=...)` is **`config.json`'s `credentials.{credential_name}`** (`api_key` or `keys[key_name]`) → **the `shared` section of `vault.json`** (the key name is the string passed as argument `env_var`) → **`shared/credentials.json` (legacy, key is `env_var`)** → **environment variable `env_var`** (`core/credentials.py`).

```python
from __future__ import annotations

import logging
from typing import Any

logger = logging.getLogger(__name__)


def get_tool_schemas() -> list[dict]:
    return [
        {
            "name": "myapi_query",
            "description": "APIにクエリを送信して結果を取得する",
            "input_schema": {
                "type": "object",
                "properties": {
                    "query": {"type": "string", "description": "検索クエリ"},
                    "limit": {"type": "integer", "description": "最大件数", "default": 10},
                },
                "required": ["query"],
            },
        },
        {
            "name": "myapi_post",
            "description": "APIにデータを送信する",
            "input_schema": {
                "type": "object",
                "properties": {
                    "data": {"type": "string", "description": "送信データ"},
                },
                "required": ["data"],
            },
        },
    ]


class MyAPIClient:
    def __init__(self) -> None:
        from core.credentials import get_credential

        self._api_key = get_credential(
            "myapi",
            "myapi_tool",
            env_var="MYAPI_KEY",
        )

    def query(self, query: str, limit: int = 10) -> list[dict]:
        import httpx

        resp = httpx.get(
            "https://api.example.com/search",
            params={"q": query, "limit": limit},
            headers={"Authorization": f"Bearer {self._api_key}"},
            timeout=30.0,
        )
        resp.raise_for_status()
        return resp.json()["results"]

    def post(self, data: str) -> dict:
        import httpx

        resp = httpx.post(
            "https://api.example.com/data",
            json={"data": data},
            headers={"Authorization": f"Bearer {self._api_key}"},
            timeout=30.0,
        )
        resp.raise_for_status()
        return resp.json()


def dispatch(name: str, args: dict[str, Any]) -> Any:
    args.pop("anima_dir", None)
    client = MyAPIClient()
    if name == "myapi_query":
        return client.query(query=args["query"], limit=args.get("limit", 10))
    if name == "myapi_post":
        return client.post(data=args["data"])
    raise ValueError(f"Unknown tool: {name}")
```

**Per-Anima authentication** (Chatwork, etc.): There is a pattern where the Anima name is taken from `args.get("anima_dir")` and an **Anima-specific key** like `CHATWORK_API_TOKEN__{anima_name}` is resolved via `resolve_env_style_credential(...)` (e.g., `resolve_identity` of `core/integrations/_chatwork_identity.py`. If not registered, raise an error without falling back). The same key naming can be used in custom tools.

#### `cli_main` (for animaworks-tool)

`animaworks-tool <tool_name> …` cannot run the CLI for core, common, or personal modules unless the module has `cli_main` (see `cli_dispatch` in `cli/tool_dispatch.py`). The typical pattern is to parse subcommands with `argparse` and call `dispatch(f"{tool}_{action}", args_dict)` internally. If you want to generate usage from a schema, also refer to `auto_cli_guide` in `core/integrations/_base.py`.

### Step 3: Saving the File

Personal tools:

```
write_memory_file(path="tools/my_tool.py", content=<コード>)
```

`tool_creation.personal` must be permitted.

### Step 4: Tool Activation (Hot Reload)

Only when adding or changing `tools/*.py` or `common_tools/*.py` **after** process startup:

```
refresh_tools()
```

The file-based map of `ExternalToolDispatcher` within the same session is rescanned, and new module names are resolved from `use_tool` (usually unnecessary for files that existed before startup).

### Step 5: Sharing (Optional)

```
share_tool(tool_name="my_tool")
```

Copied to `~/.animaworks/common_tools/`. `tool_creation.shared` is required. Other Animas each need their own `refresh_tools` (or automatic discovery at restart).

## Required Interfaces

| Function / Constant | Required | Description |
|-------------|------|------|
| `get_tool_schemas()` | **Strongly recommended** for personal and shared | For schema loading and guide generation. Even in core, some modules have empty lists (e.g., `web_search` is `[]`). **Important**: `ExternalToolDispatcher.dispatch` (the path that passes the schema name directly via `tool_use`) matches modules only for schemas included in the **`name` list of `get_tool_schemas()`** in core. Empty modules are not hit on the core side via that path. On the other hand, **`use_tool`** imports the module directly from `TOOL_MODULES` and calls `dispatch`, so **even with an empty schema list, execution is possible if `dispatch` exists**. Custom tools should be aware of both paths; defining the schema is usually safer. |
| `dispatch(name, args)` | **Recommended** | `ExternalToolDispatcher._call_module` takes priority. |
| Function with the same name as the schema name | Alternative | Used when `dispatch` is absent: `getattr(mod, name)(**args)`. |
| `cli_main(argv)` | **Required for CLI use** | `animaworks-tool` entry. |
| `EXECUTION_PROFILE` | Optional | `expected_seconds`, `background_eligible`; in core tools, **`gated: True`** can require an allowlist for send-type operations (`core/tooling/permissions.py`). |

## Invocation and schema names

- **`use_tool`**: Passed to the module’s `dispatch` (or a function with the same name) by `schema_name = f"{tool_name}_{action}"`. Authorization checks: **core**: `tool_registry` (`tool_name` must be included in the result of `get_permitted_tools`); **file-based (shared and personal)**: the merged `_personal_tools` must contain `tool_name` (`_handle_use_tool` of `core/tooling/handler.py`).
- **`animaworks-tool`**: If the first token is `submit`, it is submitted as a background job (see below). **Core** imports from `TOOL_MODULES` and `cli_main`; **shared and personal** load from a file and `cli_main`. An unknown first argument may fall back to the main CLI (`animaworks`) (`cli/tool_dispatch.py`).
- **Gated subcommands (core only)**: If the relevant action in `EXECUTION_PROFILE` has `"gated": True`, it is blocked in both the CLI and dispatch unless **`{tool_name}_{action}`** (e.g., `gmail_send`) is included in the allowed set of `permissions`. **File-based personal and shared tools** are not in `TOOL_MODULES`, so they are not subject to this gate mechanism.

## Schema Normalization

`_normalise_schema` of `core/tooling/schemas/loader.py` receives `input_schema` / `parameters` and normalizes them to `parameters` in the internal representation.

## permissions (tool_creation, external tools)

- **Loading**: `load_permissions(anima_dir)` (`core/config/schemas.py`). **`permissions.json` takes priority**. Only when absent, parse `permissions.md` to generate JSON and migrate (`migrate_permissions_md_to_json`).
- **Tool creation** (JSON example):

```json
{
  "version": 1,
  "tool_creation": {
    "personal": true,
    "shared": false
  }
}
```

The Markdown "Tool Creation" section (`個人ツール` / `共有ツール` lines) also becomes the same structure during migration.

- **External tools (core)**: `external_tools` collects, via `get_permitted_tools`, the **module names of core `TOOL_MODULES`** and the **`{tool}_{action}`** strings for gate release (e.g., `gmail_send`). In `use_tool`, core tools use names in this set on the `tool_registry` side; **personal and shared tools** are executed even outside the core set if the name exists in **`_personal_tools` after startup merge or `refresh_tools`** (files with the same name as core are skipped during discovery, so no conflict).

## EXECUTION_PROFILE

- **`background_eligible: True`**: `animaworks-tool submit <tool> <subcommand> …` registers the input from `task_type="command"` into the TaskStore, and `PendingTaskExecutor` retrieves and executes the attempt (see `_handle_submit` in `cli/tool_dispatch.py`). Execution results are also saved to `state/background_tasks/{task_id}.json`. Profile references are only applied to **importable core modules** (file tools are less likely to be flagged as warnings at submit time).
- **`gated: True`**: For the corresponding core tool actions, explicit permission for `tool_action` must be granted via permissions.

```python
EXECUTION_PROFILE: dict[str, dict[str, object]] = {
    "pipeline": {"expected_seconds": 1800, "background_eligible": True},
    "send": {"expected_seconds": 15, "background_eligible": False, "gated": True},
}
```

## Adding Core Tools to the Repository

1. Add `core/integrations/{name}.py` (items starting with `_` are excluded from scanning).
2. `TOOL_MODULES` is automatically registered via `discover_core_tools()`. No manual list for `core/integrations/__init__.py` is needed.
3. The curated allowlist for MCP is `MCP_TOOL_NAMES` in `core/tooling/surface.py`. `resolve_tool_surface` performs filtering based on trigger and role in MCP usage modes (S / C / D / G / X). Examples: `search_memory`, `read_memory_file`, `write_memory_file`, `archive_memory_file`, `send_message`, `post_channel`, `call_human`, `delegate_task`, `submit_tasks`, `update_task`, `create_skill`. **External service core tools such as Slack / Gmail / `web_search` do not appear in MCP** — they typically go through **`use_tool` / Bash (`animaworks-tool`) / skills**.
4. Add tests to `tests/`. If schemas or reference documents are auto-generated, also check the targets in `scripts/generate_reference.py`.
5. For destructive operations, consider updating `gated: True` and the permission descriptions.

## Validation Checklist

- [ ] File name: snake_case, `.py`, no leading `_` (to be included in scanning)
- [ ] Add `from __future__ import annotations` at the top (project convention)
- [ ] `get_tool_schemas()` returns the correct schema name (personal, shared)
- [ ] Process all schemas via `dispatch` or the schema-name function
- [ ] If `anima_dir` is not used, avoid side effects with `args.pop("anima_dir", None)`
- [ ] Implement `cli_main` and verify operation with `animaworks-tool`
- [ ] Add `timeout=` for external HTTP
- [ ] Authentication uses `get_credential` (or per-anima resolution of the same type as core)
- [ ] Use `logging.getLogger(__name__)` for logging (recommended)

## Security

1. Do not embed secrets in code. Use `get_credential` / vault / config.
2. Do not touch other Animas' directories.
3. In core, design "write/send" operations with `gated` and permissions as a set.

## Reference Implementations

- Thin entry + `_client` / `_cli` split: `core/integrations/chatwork.py`, `slack.py`, `discord.py`
- Authentication and API: `core/integrations/gmail.py`, `github.py`, `notion.py`, `google_calendar.py`, `google_tasks.py`
- Long-running and pipeline: `core/integrations/image_gen.py` (facade, `image/` subpackage + `EXECUTION_PROFILE`)
- Search and local LLM: `core/integrations/web_search.py` (if `get_tool_schemas` is empty, it will not match via the core path in `ExternalToolDispatcher.dispatch`; `use_tool` is possible with `dispatch`), `x_search.py`, `local_llm.py`
- Dispatcher and CLI entry: `core/tooling/dispatch.py`, `cli/tool_dispatch.py` (`cli_dispatch` / `_handle_submit`)

## Notes

- Tools are executable Python. They are distinct from skills (Markdown).
- Only tools added **after startup** require **`refresh_tools`** (files that existed before startup are already scanned at startup).
- Personal and shared files with the same name as core files are not adopted.


---
Source attribution: xuiltul
Original project: https://github.com/xuiltul/animaworks/blob/fac2093fdbced1ddc59755caa2808f91044240a8/templates/en/common_skills/tool-creator/SKILL.md
License: Apache-2.0
License information: https://www.apache.org/licenses/LICENSE-2.0
Original upstream instructions; downloaded from Mega AI Hub.

## Upstream license notice


                                 Apache License
                           Version 2.0, January 2004
                        http://www.apache.org/licenses/

   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION

   1. Definitions.

      "License" shall mean the terms and conditions for use, reproduction,
      and distribution as defined by Sections 1 through 9 of this document.

      "Licensor" shall mean the copyright owner or entity authorized by
      the copyright owner that is granting the License.

      "Legal Entity" shall mean the union of the acting entity and all
      other entities that control, are controlled by, or are under common
      control with that entity. For the purposes of this definition,
      "control" means (i) the power, direct or indirect, to cause the
      direction or management of such entity, whether by contract or
      otherwise, or (ii) ownership of fifty percent (50%) or more of the
      outstanding shares, or (iii) beneficial ownership of such entity.

      "You" (or "Your") shall mean an individual or Legal Entity
      exercising permissions granted by this License.

      "Source" form shall mean the preferred form for making modifications,
      including but not limited to software source code, documentation
      source, and configuration files.

      "Object" form shall mean any form resulting from mechanical
      transformation or translation of a Source form, including but
      not limited to compiled object code, generated documentation,
      and conversions to other media types.

      "Work" shall mean the work of authorship, whether in Source or
      Object form, made available under the License, as indicated by a
      copyright notice that is included in or attached to the work
      (an example is provided in the Appendix below).

      "Derivative Works" shall mean any work, whether in Source or Object
      form, that is based on (or derived from) the Work and for which the
      editorial revisions, annotations, elaborations, or other modifications
      represent, as a whole, an original work of authorship. For the purposes
      of this License, Derivative Works shall not include works that remain
      separable from, or merely link (or bind by name) to the interfaces of,
      the Work and Derivative Works thereof.

      "Contribution" shall mean any work of authorship, including
      the original version of the Work and any modifications or additions
      to that Work or Derivative Works thereof, that is intentionally
      submitted to the Licensor for inclusion in the Work by the copyright owner
      or by an individual or Legal Entity authorized to submit on behalf of
      the copyright owner. For the purposes of this definition, "submitted"
      means any form of electronic, verbal, or written communication sent
      to the Licensor or its representatives, including but not limited to
      communication on electronic mailing lists, source code control systems,
      and issue tracking systems that are managed by, or on behalf of, the
      Licensor for the purpose of discussing and improving the Work, but
      excluding communication that is conspicuously marked or otherwise
      designated in writing by the copyright owner as "Not a Contribution."

      "Contributor" shall mean Licensor and any individual or Legal Entity
      on behalf of whom a Contribution has been received by the Licensor and
      subsequently incorporated within the Work.

   2. Grant of Copyright License. Subject to the terms and conditions of
      this License, each Contributor hereby grants to You a perpetual,
      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
      copyright license to reproduce, prepare Derivative Works of,
      publicly display, publicly perform, sublicense, and distribute the
      Work and such Derivative Works in Source or Object form.

   3. Grant of Patent License. Subject to the terms and conditions of
      this License, each Contributor hereby grants to You a perpetual,
      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
      (except as stated in this section) patent license to make, have made,
      use, offer to sell, sell, import, and otherwise transfer the Work,
      where such license applies only to those patent claims licensable
      by such Contributor that are necessarily infringed by their
      Contribution(s) alone or by combination of their Contribution(s)
      with the Work to which such Contribution(s) was submitted. If You
      institute patent litigation against any entity (including a
      cross-claim or counterclaim in a lawsuit) alleging that the Work
      or a Contribution incorporated within the Work constitutes direct
      or contributory patent infringement, then any patent licenses
      granted to You under this License for that Work shall terminate
      as of the date such litigation is filed.

   4. Redistribution. You may reproduce and distribute copies of the
      Work or Derivative Works thereof in any medium, with or without
      modifications, and in Source or Object form, provided that You
      meet the following conditions:

      (a) You must give any other recipients of the Work or
          Derivative Works a copy of this License; and

      (b) You must cause any modified files to carry prominent notices
          stating that You changed the files; and

      (c) You must retain, in the Source form of any Derivative Works
          that You distribute, all copyright, patent, trademark, and
          attribution notices from the Source form of the Work,
          excluding those notices that do not pertain to any part of
          the Derivative Works; and

      (d) If the Work includes a "NOTICE" text file as part of its
          distribution, then any Derivative Works that You distribute must
          include a readable copy of the attribution notices contained
          within such NOTICE file, excluding any notices that do not
          pertain to any part of the Derivative Works, in at least one
          of the following places: within a NOTICE text file distributed
          as part of the Derivative Works; within the Source form or
          documentation, if provided along with the Derivative Works; or,
          within a display generated by the Derivative Works, if and
          wherever such third-party notices normally appear. The contents
          of the NOTICE file are for informational purposes only and
          do not modify the License. You may add Your own attribution
          notices within Derivative Works that You distribute, alongside
          or as an addendum to the NOTICE text from the Work, provided
          that such additional attribution notices cannot be construed
          as modifying the License.

      You may add Your own copyright statement to Your modifications and
      may provide additional or different license terms and conditions
      for use, reproduction, or distribution of Your modifications, or
      for any such Derivative Works as a whole, provided Your use,
      reproduction, and distribution of the Work otherwise complies with
      the conditions stated in this License.

   5. Submission of Contributions. Unless You explicitly state otherwise,
      any Contribution intentionally submitted for inclusion in the Work
      by You to the Licensor shall be under the terms and conditions of
      this License, without any additional terms or conditions.
      Notwithstanding the above, nothing herein shall supersede or modify
      the terms of any separate license agreement you may have executed
      with Licensor regarding such Contributions.

   6. Trademarks. This License does not grant permission to use the trade
      names, trademarks, service marks, or product names of the Licensor,
      except as required for reasonable and customary use in describing the
      origin of the Work and reproducing the content of the NOTICE file.

   7. Disclaimer of Warranty. Unless required by applicable law or
      agreed to in writing, Licensor provides the Work (and each
      Contributor provides its Contributions) on an "AS IS" BASIS,
      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
      implied, including, without limitation, any warranties or conditions
      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
      PARTICULAR PURPOSE. You are solely responsible for determining the
      appropriateness of using or redistributing the Work and assume any
      risks associated with Your exercise of permissions under this License.

   8. Limitation of Liability. In no event and under no legal theory,
      whether in tort (including negligence), contract, or otherwise,
      unless required by applicable law (such as deliberate and grossly
      negligent acts) or agreed to in writing, shall any Contributor be
      liable to You for damages, including any direct, indirect, special,
      incidental, or consequential damages of any character arising as a
      result of this License or out of the use or inability to use the
      Work (including but not limited to damages for loss of goodwill,
      work stoppage, computer failure or malfunction, or any and all
      other commercial damages or losses), even if such Contributor
      has been advised of the possibility of such damages.

   9. Accepting Warranty or Additional Liability. While redistributing
      the Work or Derivative Works thereof, You may choose to offer,
      and charge a fee for, acceptance of support, warranty, indemnity,
      or other liability obligations and/or rights consistent with this
      License. However, in accepting such obligations, You may act only
      on Your own behalf and on Your sole responsibility, not on behalf
      of any other Contributor, and only if You agree to indemnify,
      defend, and hold each Contributor harmless for any liability
      incurred by, or claims asserted against, such Contributor by reason
      of your accepting any such warranty or additional liability.

   END OF TERMS AND CONDITIONS

   Copyright 2026 AnimaWorks Authors

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.



# Mega AI Hub resource metadata

Creator / publisher: xuiltul
Original project: https://github.com/xuiltul/animaworks/blob/fac2093fdbced1ddc59755caa2808f91044240a8/templates/en/common_skills/tool-creator/SKILL.md
Attribution basis: Source repository record

Fields of work: Development & Engineering
Roles: ML / AI Engineer, Backend Developer, DevOps / SRE
Specialties: Backend, API
Tools: Animaworks
Country applicability: Country not specified
Classification basis: Source category, role and specialization labels
Instruction SHA-256: 4b9ef0b7271ed666969b13c17a0105278597ceb3f451a9ce4fa2ff2abadc58f8
