Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions FEATURE_PARITY.md
Original file line number Diff line number Diff line change
Expand Up @@ -207,7 +207,7 @@ This document tracks feature parity between IronClaw (Rust implementation) and O
| Post-compaction read audit | ✅ | ❌ | Layer 3: workspace rules appended to summaries |
| Post-compaction context injection | ✅ | ❌ | Workspace context as system event |
| Custom system prompts | ✅ | ✅ | Template variables, safety guardrails |
| Skills (modular capabilities) | ✅ | ✅ | Prompt-based skills with trust gating, attenuation, activation criteria, catalog, selector, and loaded bundle-root metadata |
| Skills (modular capabilities) | ✅ | ✅ | Prompt-based skills with trust gating, attenuation, activation criteria, catalog, selector, loaded bundle-root metadata, and scoped bundled-file reads |
| Skill routing blocks | ✅ | 🚧 | ActivationCriteria (keywords, patterns, tags) but no "Use when / Don't use when" blocks |
| Skill path compaction | ✅ | ❌ | ~ prefix to reduce prompt tokens |
| Thinking modes (off/minimal/low/medium/high/xhigh/adaptive) | ✅ | ❌ | Configurable reasoning depth |
Expand Down Expand Up @@ -550,7 +550,7 @@ This document tracks feature parity between IronClaw (Rust implementation) and O
- ✅ Cron job scheduling (routines)
- ✅ CLI subcommands (onboard, config, status, memory)
- ✅ Gateway token auth
- ✅ Skills system (prompt-based with trust gating, attenuation, activation criteria, and loaded bundle-root metadata)
- ✅ Skills system (prompt-based with trust gating, attenuation, activation criteria, loaded bundle-root metadata, and scoped bundled-file reads)
- ✅ Session file permissions (0o600)
- ✅ Memory CLI commands (search, read, write, tree, status)
- ✅ Shell env scrubbing + command injection detection
Expand Down
40 changes: 23 additions & 17 deletions docs/agent-skills-support.md
Original file line number Diff line number Diff line change
Expand Up @@ -387,16 +387,18 @@ hard-coded read-only allowlist. The current allowlist is intentionally small:
- `json`
- `skill_list`
- `skill_search`
- `skill_read_file`

This is stronger than post-hoc approval checking because the filtered-out tools
do not appear in the model prompt at all.

### 7.2 Practical effect on skill management

The attenuation list includes `skill_list` and `skill_search`, but not
`skill_install` or `skill_remove`. In practice, that means an installed skill
can remain discoverable and inspectable, but it cannot grant the model the
ability to install or remove skills through its own prompt.
The attenuation list includes `skill_list`, `skill_search`, and
`skill_read_file`, but not `skill_install` or `skill_remove`. In practice, that
means an installed skill can remain discoverable, searchable, and able to read
its own bundled reference material, but it cannot grant the model the ability
to install or remove skills through its own prompt.

That is one of the main security properties of the current subsystem.

Expand Down Expand Up @@ -484,13 +486,15 @@ It does not inject:

- the skill's filesystem path
- the source root
- ancillary bundled files
- a dedicated skill-file read tool
- ancillary bundled files inline

That is a real limitation, not just a documentation omission. The current
subsystem records enough runtime metadata for a future skill-scoped file reader,
but remains a `SKILL.md` prompt-body injector rather than a general skill-bundle
runtime.
Ancillary bundled files are deliberately accessed lazily through the
`skill_read_file` tool. The tool accepts a canonical skill identifier and a
bundle-relative path, then delegates to `src/skills/file_read.rs` for path
policy and filesystem checks. The adapter in
`src/tools/builtin/skill_tools.rs` only translates JSON parameters and
responses; it must not duplicate path policy or call the generic `read_file`
tool.

## 9. Extension points

Expand All @@ -504,6 +508,7 @@ Table 5. Main extension points in the current design.
| New activation logic | Change `prefilter_skills()` scoring or add more deterministic inputs. |
| New management surface | Add tool, command, or web handlers that call the registry. |
| Richer context injection | Extend dispatcher wrapping or `Reasoning::with_skill_context()`. |
| Bundled file read policy | Change `src/skills/file_read.rs` and keep adapters thin. |
| Stronger operator validation | Extend `doctor` or add settings checks around the registry and catalog. |

The current design keeps these seams fairly local. The parser, registry,
Expand All @@ -529,19 +534,20 @@ The current implementation has several important constraints:
or channel metadata.
- skill injection is limited to the interactive dispatcher path and does not
currently apply to worker jobs, routines, or the OpenAI-compatible proxy.
- the runtime injects only the selected `SKILL.md` body, not a file path,
ancillary references, or the private filesystem root.
- there is no dedicated skill-scoped file-reading tool in the live runtime.
- the runtime injects only the selected `SKILL.md` body, not ancillary
references or the private filesystem root.
- `skill_read_file` is read-only and inline-text-only. It does not list
directories, glob files, expose absolute paths, return base64 assets, or
fetch binary content.
- the read-only allowlist for installed skills is hard-coded, so expanding the
skill-safe tool surface requires code changes.
- `skill_install` supports exactly one of `content`, `url`, or `name`, and its
tool schema no longer always requires `name`. The exact-one-source rule is
enforced at runtime because the OpenAI-compatible schema subset used by this
project forbids top-level `oneOf`.
- validated `.skill` installs now preserve bundled `references/` and `assets/`
on disk, and loaded skills retain canonical root and entrypoint metadata, but
the runtime still injects only `SKILL.md` and does not yet expose a
skill-scoped file-reading interface.
- validated `.skill` installs preserve bundled `references/` and `assets/` on
disk, loaded skills retain canonical root and entrypoint metadata, and
`skill_read_file` can read allowed bundle-relative text files on demand.
- rediscovery infers the package kind from the installed tree. A tree with
`references/` or `assets/` is treated as a bundle; a tree containing only
`SKILL.md` is indistinguishable from a raw markdown install and is treated as
Expand Down
2 changes: 1 addition & 1 deletion docs/axinite-architecture-overview.md
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,7 @@ Table 2. AppBuilder phases and the state they add.
| Secrets | Creates the encrypted secrets store when a master key is available, injects stored provider credentials into the config overlay, and falls back to operating system credentials when no encrypted store is available | LLM credential resolution intentionally happens more than once |
| LLM | Builds the provider chain and any recording wrapper used for tracing | The chain is responsible for retry, failover, and routing decorators |
| Tools and workspace | Creates the safety layer, tool registry, embedding provider, workspace memory, and optional image or builder tools | Workspace memory only exists when a database backend is active |
| Skills | [`init_skills()`](./developers-guide.md#init_skills) discovers local and installed skills, records canonical runtime roots and `SKILL.md` entrypoints in `LoadedSkill`, wires skill tools into the `ToolRegistry`, and exposes the registry and catalog handles used by the shared staged install path for raw `SKILL.md` content and validated passive `.skill` bundles | Runs during construction only; `RuntimeSideEffects` does not load skills. Active-skill prompts expose logical bundle-relative metadata, not private host filesystem roots |
| Skills | [`init_skills()`](./developers-guide.md#init_skills) discovers local and installed skills, records canonical runtime roots and `SKILL.md` entrypoints in `LoadedSkill`, wires skill tools into the `ToolRegistry`, and exposes the registry and catalog handles used by the shared staged install path for raw `SKILL.md` content, validated passive `.skill` bundles, and scoped bundled-file reads | Runs during construction only; `RuntimeSideEffects` does not load skills. Active-skill prompts expose logical bundle-relative metadata, not private host filesystem roots. `skill_read_file` resolves only bundle-relative paths through `src/skills/file_read.rs` rather than the generic filesystem tools |
| Extensions | Starts MCP session and process managers, creates the WASM runtime, loads runtime extensions, loads registry metadata, and creates the extension manager | The extension manager is registered back into the tool system so the agent can discover and manage extensions in chat |
<!-- markdownlint-enable MD013 MD060 -->

Expand Down
35 changes: 31 additions & 4 deletions docs/developers-guide.md
Original file line number Diff line number Diff line change
Expand Up @@ -481,6 +481,7 @@ The skills sub-system is split into two top-level modules:
| Module | Purpose |
| --- | --- |
| `src/skills/bundle/` | ZIP archive sniffing, path parsing, and passive bundle validation |
| `src/skills/file_read.rs` and `src/skills/file_read/` | Runtime `skill_read_file` response types, bundle-relative path policy, and scoped file I/O |
| `src/skills/install_source.rs` | Shared blankness and trimming helpers used by install adapters before they choose a source mode |
| `src/skills/registry/` | In-memory registry; discovery, loading, staged install, removal |

Expand Down Expand Up @@ -1585,15 +1586,41 @@ The builder defaults: version `1.0.0`, trust `Trusted`, source `/tmp`,
`location` override is accepted via `.location(LoadedSkillLocation::new(...))`;
if omitted, the builder derives `SingleFile` from `/tmp/SKILL.md`.

##### Scoped skill file reads (roadmap 1.3.4)

`src/skills/file_read.rs` owns the domain contract for `skill_read_file`.
Adapters must pass a loaded `LoadedSkill` and the requested bundle-relative
path into `read_skill_file(...)` rather than resolving filesystem paths
themselves.

The policy accepts only `SKILL.md`, files under `references/`, and files under
`assets/`. It rejects absolute paths, traversal, backslashes, nested
`SKILL.md`, unsupported roots, symlinks, non-regular files, and targets whose
canonical path does not remain under the loaded skill root. It also rechecks
metadata after opening the file to avoid replacement races.

The response model returns inline UTF-8 text for readable files. Unknown
skills, disallowed paths, missing files, invalid UTF-8, I/O failures, oversized
files, and binary assets use typed JSON payloads. Binary assets and oversized
files include non-inline metadata; they do not return base64 content in this
phase.

The built-in adapter is `SkillReadFileTool` in
`src/tools/builtin/skill_tools.rs`. It looks up the skill in `SkillRegistry`,
drops the registry lock before async file I/O, and serializes the domain
response into `ToolOutput::success(...)`.

##### rstest-bdd

`rstest-bdd = "0.5.0"` and `rstest-bdd-macros = "0.5.0"` (with
`compile-time-validation`) are `[dev-dependencies]` added for behavioural tests
introduced in 1.3.3. They are used in
introduced in 1.3.3 and extended in 1.3.4. They are used in
`src/agent/dispatcher/tests/skill_bundle_context_bdd.rs` to validate the
model-facing active-skill prompt contract. The `compile-time-validation` feature
causes the macro to verify that every step referenced in a `.feature` file has a
matching Rust step function at compile time.
model-facing active-skill prompt contract and in
`src/tools/builtin/skill_tools/features/skill_read_file.feature` to validate
the model-facing bundled-file read behaviour. The `compile-time-validation`
feature causes the macro to verify that every step referenced in a `.feature`
file has a matching Rust step function at compile time.

See `execplans/1-3-3-persist-canonical-skill-roots-in-the-loaded-model.md` for
the full implementation history.
Expand Down
Loading
Loading