Skip to content

[backend] ToolRegistryBackend — load custom tools + skills from a registry, not filesystem walks #64

@dep0we

Description

@dep0we

Background

Custom tools live as tools/<name>.md (descriptor) + tools/<name>.py (implementation), discovered by walking the filesystem. Skills live as skills/<name>/SKILL.md + supporting files, also discovered by filesystem walk.

The discovery + load path is hard-coded:

  • Read directory entries
  • Parse <name>.md for descriptor
  • Import <name>.py (custom tools) or read instructions inline (skills)
  • Build registry, register with the agent's tool loop

Loading a tool from a database, a remote registry, or a private package index isn't expressible.

Why it matters

The tools/skills primitives are the natural extension surface for atomic-agents. Filesystem-only loading caps the ecosystem at "files on the box." Things filesystem-only blocks:

  • Plugin marketplace. A registry of community tools (think pip, npm) installable per-agent. Today an operator copies a tool's two files into tools/. With a registry: agent.tools.install("github.com/someone/web-scraper").
  • Versioned tools. Tool X at version 1.2 vs 1.3, with the agent pinning a version. Filesystem has no version semantics.
  • Sandboxed execution. Some tools should run in a separate process / container. Loading them inline as Python imports is the wrong shape; the protocol could express "run this tool's body in a subprocess by id."
  • Per-agent tool subset. SaaS tenants get different tool catalogs. Today every agent walks its own filesystem; a MultiTenantRegistryBackend selects the catalog by tenant.
  • Audit / approval flows. "Operator must approve before tool X is loaded." Hooks at the registry level, not buried in agent init.

What to change

  1. New module atomic_agents/registry/ with backend.py (Protocol) + filesystem.py (default wrapping current FS walks).
  2. ToolRegistryBackend protocol exposes:
    • list_tools() → list of ToolRef
    • load_tool(name)Tool (descriptor + invocable handle)
    • list_skills() / load_skill(name) (mirrors memory's pattern of progressive disclosure for skills — see spec/13)
    • install(source, version) / uninstall(name) (optional capability)
    • validate(name) (sandbox check before live load)
  3. agent.__init__ picks up agent.registry.list_tools() and registers them through the existing ToolRegistry.
  4. Skills loader (load_skill / load_skill_file framework tools) reroutes through agent.registry.load_skill_file(name, path).
  5. Spec doc docs/spec/25-registry-backend.md.

Future backends

  • PyPIToolRegistryBackend — install tools from PyPI as atomic-agents-tool-* packages
  • GitToolRegistryBackend — install tools from git URLs (pinned by SHA)
  • RemoteRegistryBackend — internal company registry (auth + RBAC)
  • LocalDevRegistryBackend — fast iteration, no install step

Acceptance

  • Existing custom tools tests + skills tests pass with FilesystemToolRegistryBackend as default.
  • Protocol conformance suite (~12 tests) — list, load, validate, install/uninstall (capability-gated).
  • One non-FS mock backend proves the protocol holds.
  • Existing tool-collision detection (ToolNameCollision, MCP review) survives the indirection.

Open questions

  • Does MCPServerRegistry (currently mcp.md → server registry) merge into this, or stay separate? They're shaped differently (servers are processes, tools are functions) but conceptually both are tool catalogs.
  • Versioning semantics: pip-style (one version per agent), npm-style (multiple versions coexist), git-style (SHA-pinned)? Probably pin-by-version per-agent, surfaced through the profile backend.
  • Sandboxing protocol: explicit run_sandboxed(tool, args) separate from load_tool? Or capability-gated within load_tool?

Context

Metadata

Metadata

Assignees

No one assigned

    Labels

    backendProtocol-pattern backend abstractions (memory, logs, locks, etc.)enhancementNew feature or request

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions