[P0] Converge skills into prompt compiler and add permanent RLM operator context #451

Closed
opened 2026-09-10 21:18:24 +00:00 by nsaspy · 1 comment
Owner

Parent/related: #117, #173, #174, #176, #172

Goal

Make skills a first-class part of the one existing provider-context compiler, then use that machinery to ship a small set of RLM operating skills that are enabled by default and remain present throughout an RLM/agent run unless trusted host configuration disables them.

This is the ADARD decision for the current skills/RLM-context work. No code is part of this issue creation.

Research findings

Agent Skills

The open Agent Skills specification defines SKILL.md as portable instructions plus metadata/resources and recommends progressive disclosure: metadata first, full instructions after activation, resources on demand. It provides metadata as a string->string extension point; allowed-tools is experimental and must not be treated as authority.

The client implementation guide also explicitly recommends protecting activated skill instructions from later context compaction because silently losing skill instructions degrades agent behavior. It allows harness-side/programmatic injection of skill content; model-driven activation is only one possible client strategy.

References:

Recursive Language Models

The RLM paper/runtime treats context interaction and recursive sub-calls as part of the model's operating environment. The authors' reference implementation uses a default system prompt that explicitly teaches the model how to use context, llm_query/rlm_query, and finalization; it also exposes a custom system-prompt override. Operational RLM instructions therefore must be guaranteed provider-visible runtime context, not merely implicit knowledge.

References:

Typed/symbolic RLM research also supports keeping recursion/control flow explicit rather than relying on unconstrained free-form execution:

Prolog constraints

SWI-Prolog CLP(FD) is explicitly intended for declarative integer reasoning and combinatorial problems such as planning, scheduling, and allocation. The agent should recognize those problem classes and prefer an available constraint capability over model guessing.

Reference:

Current repository findings

#173 already freezes the correct architecture

#173 says:

SKILL.md
 -> normalized_skill
 -> existing prompt_unit{unit:skill(...)} IR
 -> existing rlm_prompt_compiler

It explicitly rejects a second prompt compiler/skill IR and makes provider visibility and mandatory-context policy host-owned.

PR #122 currently diverges from that decision

PR #122 (feature/117-prolog-skill-activation) has useful loader/confinement/resource/default-corpus work, but it also implements a separate skill_compile/4 selector with its own lexical scoring, thresholds, count/token limits, dependency resolution and fingerprinting, then merges selected skill text into planner_instruction through rlm_skill_completion.

That selection path overlaps the already-landed rlm_prompt_compiler, which already supports kind:skill, dependencies, conflicts, capabilities, packing, reasons and fingerprints.

PR #122 should therefore be reconciled as loader/normalizer + compatibility adapter + package/resource layer, not preserved as a second independent provider-context selector.

At the time of this decision, current main is 982bad23c59dba0dd9157c1904e7723950889717; PR #122 head is 1a34d01dad9020a72a17b9bbae2a698451f575aa and is substantially diverged from current main.

#174 has the right generic permanent-visibility primitive

activation:always should apply to ordinary prompt units, not only tools. mandatory_context:true remains the post-selection packing invariant. Natural-language negation must not unpin a host-pinned unit. Trusted host disable/narrowing may.

#176 is the provider-surface gate

The design is incomplete until the actual provider-bound request is compiled from the prompt compiler. Internal selected/active_units state is not sufficient evidence that the model received the instructions.

Decision

1. One compiler

There is one canonical provider-context selector/packer:

SKILL.md loader/normalizer
        |
        v
prompt_unit{unit:skill(...)}
        |
        v
rlm_prompt_compiler
        |
        +--> permanent active units
        +--> relevant active units
        +--> active tool schemas
        +--> provider-visible instructions/resources
        v
provider renderer/request

rlm_skill may own filesystem discovery, standard/vendor parsing, normalization, lazy resources and package security. It must not own a competing routing/scoring/packing engine.

2. Permanent context is host policy

An ordinary skill/tool/instruction can be host-pinned:

activation:always
mandatory_context:true
provider_visible:true

Meaning:

  • no lexical/relevance evidence required;
  • ordinary candidate limits cannot evict it;
  • user/model prose cannot disable it;
  • context packing cannot silently omit it;
  • insufficient budget fails structurally;
  • only trusted host configuration can disable/narrow it.

A SKILL.md package MUST NOT be able to mark itself permanent/mandatory/trusted. #173 already establishes mandatory/provider policy as host-owned. Standard/vendor activation metadata may disable or influence ordinary automatic activation, but cannot promote itself to always.

3. Default RLM operating skill bundle

Ship a small bundled set of trusted skills, enabled and pinned by the default RLM agent profile:

rlm-operate

Teach the actual typed runtime contract: available plan/context/model/tool/RLM operations, bindings/references, finalization, budget awareness, and the rule not to invent unavailable capabilities or context contents.

rlm-recurse

Teach useful recursive behavior: inspect context, decompose when useful, use rlm_subagent/recursive calls for missing or independently investigable work, give children bounded sufficient context, and aggregate returned evidence. Do not teach recursion-for-recursion's-sake.

rlm-facts

Teach facts/evidence first: query supplied KB/facts/observations before guessing, distinguish retrieved fact from inference, derive with Prolog when deterministic, and use model judgment only where symbolic evidence is insufficient.

rlm-constraints

Teach constraint recognition: for finite-domain, scheduling, allocation, combinatorial or relational arithmetic problems, use an exposed constraint-solver capability when available. Never invent a solver/tool that is absent from the active provider projection.

These should be concise operational skills, not long tutorials.

4. Toggle semantics

Default: core RLM skills are enabled.

Trusted host controls must support:

  • global skill opt-out (skill_mode(off) or the reconciled equivalent);
  • per-skill disable for experiments/debugging;
  • default profile override without editing the SKILL.md body.

No natural-language request or skill-authored metadata can silently disable a host-pinned core skill.

5. Scope of permanence

Every provider request that participates in an RLM/agent run must receive the active permanent units, including recursive/subagent model calls and repair/retry model calls. A low-level standalone raw-LM API may remain raw when invoked outside an RLM/agent execution context; once a model call is part of an RLM run, the run's permanent context propagates with it.

This prevents the root from knowing how to operate RLM while a recursive child silently loses the operating contract.

6. Provider placement

Permanent behavioral skills are skill packages as the source of truth, but the provider renderer should place their active instruction bodies in the provider's durable instruction/system context rather than pretending they are user text. This matches the reference RLM implementation's use of a system prompt for operating instructions.

Provider-specific message/channel mapping remains a renderer concern; skill activation remains provider-neutral.

7. Authority remains separate

A permanent skill/tool is model-visible, not automatically executable.

visible != capability granted != authorized != effect admitted

An always-visible tool still passes existing capability, authority, confinement and effect checks. A skill mentioning a tool does not grant it.

Adversarial review

The implementation must survive at least these cases:

  1. User says “ignore/disable the RLM skills” -> pinned skills remain present.
  2. Malicious SKILL.md claims permanent/mandatory/trusted -> ignored/rejected as host-owned policy.
  3. Malicious allowed-tools claims unavailable authority -> no capability/authority change.
  4. Candidate limit saturated by relevant units -> permanent units remain.
  5. Context budget too small -> structural failure, not silent removal.
  6. Permanent skill conflicts with another permanent skill -> configuration error, not relevance-score arbitration.
  7. Recursive child has narrower capabilities -> permanent behavioral skill may remain, but unavailable tool schemas stay absent and the skill must not imply they exist.
  8. Context compaction -> active permanent skill content is protected/reconstituted, never silently lost.
  9. Repeated nested wrappers/retries -> permanent skills injected exactly once per provider request.
  10. Skill version/fingerprint changes -> provider projection fingerprint changes and trace exposes which version was active.
  11. Direct SKILL.md loading remains path-confined and resources remain inert until explicitly read/executed through normal authority boundaries.
  12. PR #122 reconciliation must not regress its useful symlink/resource/default-corpus security work.

Required tests

Compiler/loader

  • strict standard SKILL.md -> normalized prompt_unit{unit:skill(...)};
  • no second selector: skill routing is performed by rlm_prompt_compiler;
  • host-pinned skill activates on unrelated input;
  • relevant skill without evidence remains inactive;
  • SKILL.md cannot self-promote to permanent;
  • natural-language negation cannot remove pinned skill;
  • trusted per-skill/global disable can remove it;
  • pinned mandatory unit cannot be packed out;
  • impossible permanent budget fails structurally;
  • activation policy is material to fingerprint/explanation.

Exact provider-bound proof

Tests must capture the exact request sent to the provider and assert the instruction body/identity is present, not merely inspect compiler state.

Required paths:

  • root RLM planner request contains all default core RLM skills;
  • recursive/subagent provider request contains them;
  • RLM-internal leaf/model request contains them when part of the run;
  • retry/repair request contains them;
  • unrelated task still contains them;
  • user text attempting to disable them does not remove them;
  • trusted opt-out removes them;
  • ordinary relevant skill is absent on unrelated task and present on matching task;
  • no duplicate injection.

Behavioral model tests — no spoon-fed plan

Do not use planner_instruction to provide the exact plan JSON/steps under test.

At least:

  1. decomposable fixture: model independently chooses recursive/subagent work and combines results;
  2. trivial fixture: model does not recurse unnecessarily;
  3. facts fixture: model uses authoritative supplied facts rather than inventing an answer;
  4. finite constraint fixture: with solver capability exposed, model chooses the solver path;
  5. same constraint fixture without solver exposure: model does not hallucinate the unavailable solver;
  6. unknown-information fixture: model uses an available subagent/context/tool path instead of guessing.

Reconciliation requirements

#117 / PR #122

Keep and reconcile the useful package loader, standard/vendor compatibility, resource indexing/confinement, pinned corpus and provenance work. Replace/delegate the independent skill scoring/selection/packing path with normalized prompt-unit registration into rlm_prompt_compiler, per #173.

#174

Treat activation:always as generic to all prompt units, including skill(...) and instruction(...), not a tool-only feature. Host policy owns permanent activation.

#176

Extend production provider-surface acceptance to prove permanent skill bodies and instructions reach the exact model request across the RLM run, not just tool schemas at the root planner.

#172

Skill-aware subagent delegation should inherit the parent's permanent skill set by default while still narrowing child capabilities/authority and dynamically selecting additional child-specific relevant skills.

Non-goals

  • no second skill compiler/router;
  • no special core_skill registry;
  • no hardcoded giant planner prompt;
  • no model-controlled permanence;
  • no skill-controlled authority;
  • no requirement that all ordinary skills be permanent;
  • no requirement that a standalone raw LM call outside an RLM/agent run become an RLM agent;
  • no implementation in this ADARD issue.

Acceptance decision

APPROVED architecture: standard SKILL.md loader -> normalized skill/prompt unit -> single prompt compiler -> host-pinned permanent + dynamically relevant context -> provider-bound request, with a default toggleable RLM operating skill bundle and exact-request tests proving the model actually receives it.

Parent/related: #117, #173, #174, #176, #172 ## Goal Make skills a first-class part of the **one existing provider-context compiler**, then use that machinery to ship a small set of RLM operating skills that are enabled by default and remain present throughout an RLM/agent run unless trusted host configuration disables them. This is the ADARD decision for the current skills/RLM-context work. No code is part of this issue creation. ## Research findings ### Agent Skills The open Agent Skills specification defines `SKILL.md` as portable instructions plus metadata/resources and recommends progressive disclosure: metadata first, full instructions after activation, resources on demand. It provides `metadata` as a string->string extension point; `allowed-tools` is experimental and must not be treated as authority. The client implementation guide also explicitly recommends protecting activated skill instructions from later context compaction because silently losing skill instructions degrades agent behavior. It allows harness-side/programmatic injection of skill content; model-driven activation is only one possible client strategy. References: - https://agentskills.io/specification - https://agentskills.io/client-implementation/adding-skills-support - https://platform.claude.com/docs/en/agents-and-tools/agent-skills/overview ### Recursive Language Models The RLM paper/runtime treats context interaction and recursive sub-calls as part of the model's operating environment. The authors' reference implementation uses a default **system prompt** that explicitly teaches the model how to use context, `llm_query`/`rlm_query`, and finalization; it also exposes a custom system-prompt override. Operational RLM instructions therefore must be guaranteed provider-visible runtime context, not merely implicit knowledge. References: - https://arxiv.org/abs/2512.24601 - https://github.com/alexzhang13/rlm - https://github.com/alexzhang13/rlm-minimal/blob/main/rlm/utils/prompts.py Typed/symbolic RLM research also supports keeping recursion/control flow explicit rather than relying on unconstrained free-form execution: - https://arxiv.org/abs/2603.20105 ### Prolog constraints SWI-Prolog CLP(FD) is explicitly intended for declarative integer reasoning and combinatorial problems such as planning, scheduling, and allocation. The agent should recognize those problem classes and prefer an available constraint capability over model guessing. Reference: - https://www.swi-prolog.org/man/clpfd.html ## Current repository findings ### #173 already freezes the correct architecture #173 says: ```text SKILL.md -> normalized_skill -> existing prompt_unit{unit:skill(...)} IR -> existing rlm_prompt_compiler ``` It explicitly rejects a second prompt compiler/skill IR and makes provider visibility and mandatory-context policy host-owned. ### PR #122 currently diverges from that decision PR #122 (`feature/117-prolog-skill-activation`) has useful loader/confinement/resource/default-corpus work, but it also implements a separate `skill_compile/4` selector with its own lexical scoring, thresholds, count/token limits, dependency resolution and fingerprinting, then merges selected skill text into `planner_instruction` through `rlm_skill_completion`. That selection path overlaps the already-landed `rlm_prompt_compiler`, which already supports `kind:skill`, dependencies, conflicts, capabilities, packing, reasons and fingerprints. PR #122 should therefore be reconciled as **loader/normalizer + compatibility adapter + package/resource layer**, not preserved as a second independent provider-context selector. At the time of this decision, current `main` is `982bad23c59dba0dd9157c1904e7723950889717`; PR #122 head is `1a34d01dad9020a72a17b9bbae2a698451f575aa` and is substantially diverged from current main. ### #174 has the right generic permanent-visibility primitive `activation:always` should apply to ordinary prompt units, not only tools. `mandatory_context:true` remains the post-selection packing invariant. Natural-language negation must not unpin a host-pinned unit. Trusted host disable/narrowing may. ### #176 is the provider-surface gate The design is incomplete until the actual provider-bound request is compiled from the prompt compiler. Internal `selected`/`active_units` state is not sufficient evidence that the model received the instructions. ## Decision ### 1. One compiler There is one canonical provider-context selector/packer: ```text SKILL.md loader/normalizer | v prompt_unit{unit:skill(...)} | v rlm_prompt_compiler | +--> permanent active units +--> relevant active units +--> active tool schemas +--> provider-visible instructions/resources v provider renderer/request ``` `rlm_skill` may own filesystem discovery, standard/vendor parsing, normalization, lazy resources and package security. It must not own a competing routing/scoring/packing engine. ### 2. Permanent context is host policy An ordinary skill/tool/instruction can be host-pinned: ```text activation:always mandatory_context:true provider_visible:true ``` Meaning: - no lexical/relevance evidence required; - ordinary candidate limits cannot evict it; - user/model prose cannot disable it; - context packing cannot silently omit it; - insufficient budget fails structurally; - only trusted host configuration can disable/narrow it. A `SKILL.md` package MUST NOT be able to mark itself permanent/mandatory/trusted. #173 already establishes mandatory/provider policy as host-owned. Standard/vendor activation metadata may disable or influence ordinary automatic activation, but cannot promote itself to `always`. ### 3. Default RLM operating skill bundle Ship a small bundled set of trusted skills, enabled and pinned by the default RLM agent profile: #### `rlm-operate` Teach the actual typed runtime contract: available plan/context/model/tool/RLM operations, bindings/references, finalization, budget awareness, and the rule not to invent unavailable capabilities or context contents. #### `rlm-recurse` Teach useful recursive behavior: inspect context, decompose when useful, use `rlm_subagent`/recursive calls for missing or independently investigable work, give children bounded sufficient context, and aggregate returned evidence. Do not teach recursion-for-recursion's-sake. #### `rlm-facts` Teach facts/evidence first: query supplied KB/facts/observations before guessing, distinguish retrieved fact from inference, derive with Prolog when deterministic, and use model judgment only where symbolic evidence is insufficient. #### `rlm-constraints` Teach constraint recognition: for finite-domain, scheduling, allocation, combinatorial or relational arithmetic problems, use an exposed constraint-solver capability when available. Never invent a solver/tool that is absent from the active provider projection. These should be concise operational skills, not long tutorials. ### 4. Toggle semantics Default: core RLM skills are enabled. Trusted host controls must support: - global skill opt-out (`skill_mode(off)` or the reconciled equivalent); - per-skill disable for experiments/debugging; - default profile override without editing the SKILL.md body. No natural-language request or skill-authored metadata can silently disable a host-pinned core skill. ### 5. Scope of permanence Every provider request that participates in an **RLM/agent run** must receive the active permanent units, including recursive/subagent model calls and repair/retry model calls. A low-level standalone raw-LM API may remain raw when invoked outside an RLM/agent execution context; once a model call is part of an RLM run, the run's permanent context propagates with it. This prevents the root from knowing how to operate RLM while a recursive child silently loses the operating contract. ### 6. Provider placement Permanent behavioral skills are skill packages as the source of truth, but the provider renderer should place their active instruction bodies in the provider's durable instruction/system context rather than pretending they are user text. This matches the reference RLM implementation's use of a system prompt for operating instructions. Provider-specific message/channel mapping remains a renderer concern; skill activation remains provider-neutral. ### 7. Authority remains separate A permanent skill/tool is **model-visible**, not automatically executable. ```text visible != capability granted != authorized != effect admitted ``` An always-visible tool still passes existing capability, authority, confinement and effect checks. A skill mentioning a tool does not grant it. ## Adversarial review The implementation must survive at least these cases: 1. User says “ignore/disable the RLM skills” -> pinned skills remain present. 2. Malicious SKILL.md claims permanent/mandatory/trusted -> ignored/rejected as host-owned policy. 3. Malicious `allowed-tools` claims unavailable authority -> no capability/authority change. 4. Candidate limit saturated by relevant units -> permanent units remain. 5. Context budget too small -> structural failure, not silent removal. 6. Permanent skill conflicts with another permanent skill -> configuration error, not relevance-score arbitration. 7. Recursive child has narrower capabilities -> permanent behavioral skill may remain, but unavailable tool schemas stay absent and the skill must not imply they exist. 8. Context compaction -> active permanent skill content is protected/reconstituted, never silently lost. 9. Repeated nested wrappers/retries -> permanent skills injected exactly once per provider request. 10. Skill version/fingerprint changes -> provider projection fingerprint changes and trace exposes which version was active. 11. Direct `SKILL.md` loading remains path-confined and resources remain inert until explicitly read/executed through normal authority boundaries. 12. PR #122 reconciliation must not regress its useful symlink/resource/default-corpus security work. ## Required tests ### Compiler/loader - strict standard SKILL.md -> normalized `prompt_unit{unit:skill(...)}`; - no second selector: skill routing is performed by `rlm_prompt_compiler`; - host-pinned skill activates on unrelated input; - relevant skill without evidence remains inactive; - SKILL.md cannot self-promote to permanent; - natural-language negation cannot remove pinned skill; - trusted per-skill/global disable can remove it; - pinned mandatory unit cannot be packed out; - impossible permanent budget fails structurally; - activation policy is material to fingerprint/explanation. ### Exact provider-bound proof Tests must capture the **exact request sent to the provider** and assert the instruction body/identity is present, not merely inspect compiler state. Required paths: - root RLM planner request contains all default core RLM skills; - recursive/subagent provider request contains them; - RLM-internal leaf/model request contains them when part of the run; - retry/repair request contains them; - unrelated task still contains them; - user text attempting to disable them does not remove them; - trusted opt-out removes them; - ordinary relevant skill is absent on unrelated task and present on matching task; - no duplicate injection. ### Behavioral model tests — no spoon-fed plan Do not use `planner_instruction` to provide the exact plan JSON/steps under test. At least: 1. decomposable fixture: model independently chooses recursive/subagent work and combines results; 2. trivial fixture: model does not recurse unnecessarily; 3. facts fixture: model uses authoritative supplied facts rather than inventing an answer; 4. finite constraint fixture: with solver capability exposed, model chooses the solver path; 5. same constraint fixture without solver exposure: model does not hallucinate the unavailable solver; 6. unknown-information fixture: model uses an available subagent/context/tool path instead of guessing. ## Reconciliation requirements ### #117 / PR #122 Keep and reconcile the useful package loader, standard/vendor compatibility, resource indexing/confinement, pinned corpus and provenance work. Replace/delegate the independent skill scoring/selection/packing path with normalized prompt-unit registration into `rlm_prompt_compiler`, per #173. ### #174 Treat `activation:always` as generic to **all prompt units**, including `skill(...)` and `instruction(...)`, not a tool-only feature. Host policy owns permanent activation. ### #176 Extend production provider-surface acceptance to prove permanent skill bodies and instructions reach the exact model request across the RLM run, not just tool schemas at the root planner. ### #172 Skill-aware subagent delegation should inherit the parent's permanent skill set by default while still narrowing child capabilities/authority and dynamically selecting additional child-specific relevant skills. ## Non-goals - no second skill compiler/router; - no special `core_skill` registry; - no hardcoded giant planner prompt; - no model-controlled permanence; - no skill-controlled authority; - no requirement that all ordinary skills be permanent; - no requirement that a standalone raw LM call outside an RLM/agent run become an RLM agent; - no implementation in this ADARD issue. ## Acceptance decision **APPROVED architecture:** standard SKILL.md loader -> normalized skill/prompt unit -> single prompt compiler -> host-pinned permanent + dynamically relevant context -> provider-bound request, with a default toggleable RLM operating skill bundle and exact-request tests proving the model actually receives it.
Author
Owner

Duplicate of #183 (pre-existing Forgejo mirror). Closing this accidental duplicate created by today's open-state sync; #183 stays canonical on Forgejo.

Duplicate of #183 (pre-existing Forgejo mirror). Closing this accidental duplicate created by today's open-state sync; #183 stays canonical on Forgejo.
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#451
No description provided.