[P1] Define the external tool-library loading boundary #48

Closed
opened 2026-08-16 04:01:02 +00:00 by lost-rob0t · 3 comments
lost-rob0t commented 2026-08-16 04:01:02 +00:00 (Migrated from github.com)

Goal

Keep prolog-rlm a general-purpose RLM/agent runtime library while allowing concrete tool implementations to be loaded from separate libraries.

Core must own the tool contract and loader interface, not the tool catalog.

Required boundary

prolog-rlm should continue to own:

  • rlm_tool registry lifecycle;
  • tool schemas and validation;
  • capability checking/narrowing;
  • invocation limits and tracing;
  • typed-plan integration;
  • a small API for loading/registering external tool libraries.

Concrete tools should live outside core, preferably in a companion library such as prolog-rlm-tools.

Public loading API

The loader must support both category-scoped loading and load everything.

Required user-facing predicates:

rlmLoadTools(filesystem).
rlmLoadTools(git).
rlmLoadTools(process).
rlmLoadTools(network).
rlmLoadTools(mcp).

rlmLoadAllTools.

rlmLoadTools(Category) loads/registers every installed tool belonging to that category.

rlmLoadAllTools loads/registers every installed tool exposed by the configured external tool libraries.

Tool loading and capability granting are separate operations: loading a category or all tools makes schemas/handlers available to the registry, but does not grant an agent authority to invoke them.

The category mechanism must be extensible. Third-party tool libraries may advertise additional categories without modifying core.

Acceptance criteria

  • Define a stable public API for an external library to register one or more tools into an RLM tool registry.
  • Implement rlmLoadTools(+Category) for category-scoped tool loading.
  • Implement rlmLoadAllTools/0 for loading all installed/discoverable external tools.
  • Define a stable category-advertisement contract for external tool libraries.
  • Initial categories include at least filesystem, git, process, network, and mcp.
  • Third-party libraries can define additional categories without changing prolog-rlm core.
  • Define how a tool library advertises schemas/capabilities without exposing arbitrary callables to model output.
  • Preserve narrowing-only capability semantics.
  • Loading a tool library/category/all tools does not automatically grant its capabilities.
  • Multiple independent tool libraries can be loaded into the same registry.
  • Repeated category/all loading is idempotent or returns a deterministic already-loaded result rather than silently duplicating tools.
  • Duplicate tool-name conflicts between libraries fail structurally and deterministically.
  • Unknown categories fail with a structured error and expose discoverable valid categories.
  • Add deterministic tests with multiple tiny external fixture tool libraries and categories.
  • Document the extension boundary for downstream agents.

Non-goals

  • Do not put project/git/shell/network implementations in prolog-rlm core.
  • Do not add arbitrary call/1, ambient filesystem, ambient network, or unrestricted process execution.
  • Do not couple the runtime to any one agent implementation.
  • rlmLoadAllTools must not mean grant_all_capabilities.

Design principle

prolog-rlm is the reusable execution substrate. Tool implementations are separately loadable libraries. Loading controls availability; capabilities control authority.

## Goal Keep `prolog-rlm` a general-purpose RLM/agent runtime library while allowing concrete tool implementations to be loaded from separate libraries. Core must own the **tool contract and loader interface**, not the tool catalog. ## Required boundary `prolog-rlm` should continue to own: - `rlm_tool` registry lifecycle; - tool schemas and validation; - capability checking/narrowing; - invocation limits and tracing; - typed-plan integration; - a small API for loading/registering external tool libraries. Concrete tools should live outside core, preferably in a companion library such as `prolog-rlm-tools`. ## Public loading API The loader must support both **category-scoped loading** and **load everything**. Required user-facing predicates: ```prolog rlmLoadTools(filesystem). rlmLoadTools(git). rlmLoadTools(process). rlmLoadTools(network). rlmLoadTools(mcp). rlmLoadAllTools. ``` `rlmLoadTools(Category)` loads/registers every installed tool belonging to that category. `rlmLoadAllTools` loads/registers every installed tool exposed by the configured external tool libraries. Tool loading and capability granting are separate operations: loading a category or all tools makes schemas/handlers available to the registry, but **does not grant an agent authority to invoke them**. The category mechanism must be extensible. Third-party tool libraries may advertise additional categories without modifying core. ## Acceptance criteria - [ ] Define a stable public API for an external library to register one or more tools into an RLM tool registry. - [ ] Implement `rlmLoadTools(+Category)` for category-scoped tool loading. - [ ] Implement `rlmLoadAllTools/0` for loading all installed/discoverable external tools. - [ ] Define a stable category-advertisement contract for external tool libraries. - [ ] Initial categories include at least `filesystem`, `git`, `process`, `network`, and `mcp`. - [ ] Third-party libraries can define additional categories without changing `prolog-rlm` core. - [ ] Define how a tool library advertises schemas/capabilities without exposing arbitrary callables to model output. - [ ] Preserve narrowing-only capability semantics. - [ ] Loading a tool library/category/all tools does **not** automatically grant its capabilities. - [ ] Multiple independent tool libraries can be loaded into the same registry. - [ ] Repeated category/all loading is idempotent or returns a deterministic already-loaded result rather than silently duplicating tools. - [ ] Duplicate tool-name conflicts between libraries fail structurally and deterministically. - [ ] Unknown categories fail with a structured error and expose discoverable valid categories. - [ ] Add deterministic tests with multiple tiny external fixture tool libraries and categories. - [ ] Document the extension boundary for downstream agents. ## Non-goals - Do not put project/git/shell/network implementations in `prolog-rlm` core. - Do not add arbitrary `call/1`, ambient filesystem, ambient network, or unrestricted process execution. - Do not couple the runtime to any one agent implementation. - `rlmLoadAllTools` must not mean `grant_all_capabilities`. ## Design principle `prolog-rlm` is the reusable execution substrate. Tool implementations are separately loadable libraries. Loading controls **availability**; capabilities control **authority**.
lost-rob0t commented 2026-08-17 05:55:40 +00:00 (Migrated from github.com)

Live-state reconciliation after PR #62: #48 is partially implemented on canonical main 88b64db41a4c474379a1808b95c761ffc78d9fc2 and should not be approached as a greenfield loader.

Existing core module prolog/rlm_tool_loader.pl already provides a multifile trusted external-pack ABI (tool_pack/2), pack discovery (rlm_tool_packs/1), single-pack loading (rlm_load_tools/3), load-all (rlm_load_all_tools/2), structured unknown/ambiguous/invalid-loader errors, and explicitly keeps loading separate from capability grants. test/rlm_tool_loader_test.pl already proves declarative discovery, unknown-pack failure, loading without authority grant, and explicit-capability invocation.

Remaining #48 work should therefore focus on the acceptance gaps rather than duplicating this module: category/advertisement semantics versus the current one-pack-one-name model, deterministic repeated loading/idempotency, multiple independent libraries in one registry, duplicate tool-name conflict behavior across libraries, discoverable valid categories/tools, initial category contract (filesystem, git, process, network, mcp), and documentation/public facade naming as appropriate.

This also unlocks the remaining external mcp category work in #52. Keep concrete standard tool implementations in #49/#50 rather than expanding core.

Live-state reconciliation after PR #62: #48 is partially implemented on canonical main `88b64db41a4c474379a1808b95c761ffc78d9fc2` and should not be approached as a greenfield loader. Existing core module `prolog/rlm_tool_loader.pl` already provides a multifile trusted external-pack ABI (`tool_pack/2`), pack discovery (`rlm_tool_packs/1`), single-pack loading (`rlm_load_tools/3`), load-all (`rlm_load_all_tools/2`), structured unknown/ambiguous/invalid-loader errors, and explicitly keeps loading separate from capability grants. `test/rlm_tool_loader_test.pl` already proves declarative discovery, unknown-pack failure, loading without authority grant, and explicit-capability invocation. Remaining #48 work should therefore focus on the acceptance gaps rather than duplicating this module: category/advertisement semantics versus the current one-pack-one-name model, deterministic repeated loading/idempotency, multiple independent libraries in one registry, duplicate tool-name conflict behavior across libraries, discoverable valid categories/tools, initial category contract (`filesystem`, `git`, `process`, `network`, `mcp`), and documentation/public facade naming as appropriate. This also unlocks the remaining external `mcp` category work in #52. Keep concrete standard tool implementations in #49/#50 rather than expanding core.
lost-rob0t commented 2026-08-17 06:52:14 +00:00 (Migrated from github.com)

PR #66 is the implementation slice for the remaining #48 acceptance gaps on canonical base 88b64db41a4c474379a1808b95c761ffc78d9fc2.

Implemented in the current PR head:

  • retain the existing trusted tool_pack/2 loader ABI;
  • add sanitized tool_pack_manifest/2 metadata (library, one category-scoped pack, advertised tool name/capability/effect);
  • allow one library to publish multiple category-scoped packs and multiple independent libraries to contribute to the same category;
  • add pack/library/category/catalog discovery without returning loader callables;
  • category-scoped rlm_load_tools/3, legacy exact-pack fallback, and deterministic load-all;
  • per-registry loaded/reused idempotency so repeated loads do not rely on duplicate-registration failure;
  • structured unknown-category output including current discoverable categories;
  • preflight duplicate tool-name conflicts that identify both contributing packs/libraries/categories and run before either conflicting loader;
  • deterministic fixture libraries proving multi-library composition, category isolation, load-all, malformed declarations, idempotency, capability separation and authority invariance;
  • docs/external-tool-libraries.md documenting the extension/security boundary and a third-party category example.

The PR also adds the external mcp category adapter needed by #52 without importing concrete standard tools from #49/#50.

Keeping #48 open until the exact final PR head passes both deterministic and configured REAL OpenRouter CI and is merged. If those gates stay green, this issue's remaining acceptance should be complete and it can close against the merge SHA.

PR #66 is the implementation slice for the remaining #48 acceptance gaps on canonical base `88b64db41a4c474379a1808b95c761ffc78d9fc2`. Implemented in the current PR head: - retain the existing trusted `tool_pack/2` loader ABI; - add sanitized `tool_pack_manifest/2` metadata (`library`, one category-scoped pack, advertised tool name/capability/effect); - allow one library to publish multiple category-scoped packs and multiple independent libraries to contribute to the same category; - add pack/library/category/catalog discovery without returning loader callables; - category-scoped `rlm_load_tools/3`, legacy exact-pack fallback, and deterministic load-all; - per-registry `loaded`/`reused` idempotency so repeated loads do not rely on duplicate-registration failure; - structured unknown-category output including current discoverable categories; - preflight duplicate tool-name conflicts that identify both contributing packs/libraries/categories and run before either conflicting loader; - deterministic fixture libraries proving multi-library composition, category isolation, load-all, malformed declarations, idempotency, capability separation and authority invariance; - `docs/external-tool-libraries.md` documenting the extension/security boundary and a third-party category example. The PR also adds the external `mcp` category adapter needed by #52 without importing concrete standard tools from #49/#50. Keeping #48 open until the exact final PR head passes both deterministic and configured REAL OpenRouter CI and is merged. If those gates stay green, this issue's remaining acceptance should be complete and it can close against the merge SHA.
lost-rob0t commented 2026-08-17 06:58:02 +00:00 (Migrated from github.com)

Closed by squash merge 9ba763d248f6e087b3ff01c651762997f02ee726 from PR #66.

Final exact PR head was a4a45a6eb0c753fa626a8db47016654e990d20e2. Deterministic CI was green across static production/live-definition load, full canonical PlUnit, loader/category fixtures, tool/MCP async, authority, scheduler/concurrency, benchmark/conformance (16/16), deep recursion (15/15), CLI/trace, fresh-process graph resume, durable artifact handoff, and whitespace. Production static load was warning-clean for the touched surface.

The complete configured REAL OpenRouter job was also green on that head: core including streaming/typed plan/tool/native-tool/recursive completion, structured repair, benchmark, depth 0/1/2, and CLI smoke. OPENROUTER_TEST_MODEL was unset and every request used the repository's configured openrouter/free path.

#48 acceptance is therefore complete on canonical main.

Closed by squash merge `9ba763d248f6e087b3ff01c651762997f02ee726` from PR #66. Final exact PR head was `a4a45a6eb0c753fa626a8db47016654e990d20e2`. Deterministic CI was green across static production/live-definition load, full canonical PlUnit, loader/category fixtures, tool/MCP async, authority, scheduler/concurrency, benchmark/conformance (16/16), deep recursion (15/15), CLI/trace, fresh-process graph resume, durable artifact handoff, and whitespace. Production static load was warning-clean for the touched surface. The complete configured REAL OpenRouter job was also green on that head: core including streaming/typed plan/tool/native-tool/recursive completion, structured repair, benchmark, depth 0/1/2, and CLI smoke. `OPENROUTER_TEST_MODEL` was unset and every request used the repository's configured `openrouter/free` path. #48 acceptance is therefore complete on canonical main.
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
nsaspy/prolog-rlm#48
No description provided.