ai-memory v0.8.0

Agent Skills (v0.7.0)

Status (2026-05-14): Agent Skills (Pillar 1.5) ships in v0.7.0 as the substrate ingestion path for agentskills.io-compliant SKILL.md modules. The L2 wave adds reflection-as-skill promotion (#671) and the composes_with_reflections declaration (#672) — the two halves of the closing loop between the recursive-learning primitive and a runtime-portable skill artefact. Every claim on this page maps to shipped code at commit c359e89.

ai-memory v0.7.0 ships a substrate-native ingestion path for agentskills.io-compliant skill manifests. A skill is just a SKILL.md document with a YAML frontmatter block plus an optional resources/ sub-directory; the substrate persists the manifest into a typed skills table, records its content-addressed digest, signs the row with the operator’s Ed25519 identity (when configured), and exposes a small set of MCP tools so runtimes can register, list, get, fetch resources, export, promote from a reflection, and compose with reflection memories.

This page is the engineering-precise primer. The narrative intro sits in the v0.7.0 release notes (v0.7.0/release-notes.md §”Agent Skills”). The reflection-to-skill bridge is documented from the reflection side in RECURSIVE_LEARNING.md §Reflection-as-skill.

What Agent Skills are

Agent Skills is an emerging community specification for portable, machine-readable, runtime-agnostic skill modules — a single SKILL.md file with a YAML frontmatter header, a free-form markdown body, and an optional resources/ sub-directory holding any scripts, references, or assets the skill activates against. Skills are designed to be moved across runtimes without re-authoring: the manifest is the contract, the body is the documentation, and the resources are the activation payload.

ai-memory does not ship a runtime that executes a skill — that is the host agent’s job. ai-memory ships the substrate that makes a skill portable, audit-trail-attested, content-addressed, and round-trip-stable across registration, export, and re-registration on a different node.

Substrate vs runtime relationship

Layer What ai-memory does What the host agent does
Substrate (this repo) Parses, validates, persists, content-addresses, signs, federates, exports, and round-trips the SKILL.md manifest. Provides MCP read APIs. n/a
Runtime (host agent) Reads the skill body, follows its instructions, activates resources by name. ai-memory is not in the call path. Operates against the skill body returned by memory_skill_get.

The split is deliberate. A skill is a portable contract, not a function call. The substrate’s job ends when it can hand a host agent a content-addressed, signed, optionally-composed activation payload. What the agent does with that payload is opaque to ai-memory.

MCP tools — the seven memory_skill_* verbs

The 7 MCP tools that make up the Agent Skills wire surface:

Tool Family Wave Purpose
memory_skill_register other L1-5 Register a SKILL.md from a folder (with optional resources/ sub-directory) or from inline text. Re-registering the same (name, namespace) creates a new version; the previous row is superseded.
memory_skill_list other L1-5 List current (non-superseded) skills with ~100 tokens/skill. Returns id, name, description, namespace, digest, metadata. Body is NOT decompressed — use memory_skill_get for activation.
memory_skill_get other L1-5 Return the full activation payload: metadata + decompressed body. Old version ids remain addressable after supersession (durable history).
memory_skill_resource other L1-5 Fetch a single resource by (skill_id, resource_path), digest-verified against the row’s SHA-256 before return. Errors on digest mismatch.
memory_skill_export other L1-5 Write SKILL.md + resources/ to a target folder. Re-registering from the exported folder produces the identical SHA-256 digest — the round-trip guarantee. Appends a skill.exported row to signed_events.
memory_skill_promote_from_reflection other L2-6 Promote a Reflection-kind memory (depth ≥ 1, default floor 1) to a SKILL.md-format skill. Each reflects_on source becomes a references/source_{i}.md resource. Frontmatter records derived_from_reflection_id + original_reflection_depth. The resulting digest is identical to a hand-authored SKILL.md with the same content.
memory_skill_compositional_context other L2-7 Return a skill body + reflection memories from the namespaces declared in its composes_with_reflections frontmatter list, bounded by max_reflection_depth and a caller-supplied token budget (budget_tokens, default 4000, max 32000).

(All seven report the other family in the MCP registry — crate::profile::Family::Other; they ship in --profile full.)

Total: 7 MCP tools in the memory_skill_* family. The MCP tool count grew from 60 → 63 across the L2 wave (L2-3 + memory_dependents_of_invalidated; L2-6 + memory_skill_promote_from_reflection; L2-7 + memory_skill_compositional_context). The skill-family count alone is 7 because the original L1-5 substrate landed 5 of the verbs (register, list, get, resource, export) before L2-6 and L2-7 added the closing-loop verbs.

SKILL.md format + frontmatter

A SKILL.md file is a markdown document with a YAML frontmatter block fenced by ---:

---
namespace: global
name: my-skill
description: "Does something useful."
license: Apache-2.0          # optional, SPDX expression or free-form
compatibility: ">=0.7.0"     # optional, 1-500 chars
allowed_tools:               # optional list of MCP tool names
  - memory_recall
  - memory_store
composes_with_reflections:   # v0.7.0 L2-7 — optional list
  - namespace: foo/observations
    min_depth: 1
---

Markdown body follows the closing fence.

Validation rules (per the agentskills.io spec, enforced in src/parsing/skill_md.rs):

Field Constraint
name Regex ^[a-z0-9](?:[a-z0-9-]*[a-z0-9])?$, length 1-64. No consecutive hyphens.
description 1-1024 chars, non-empty.
compatibility 1-500 chars when present.
namespace Required, non-empty.
license SPDX expression or free-form. Optional.
allowed_tools List of MCP tool names. Optional.
composes_with_reflections List of {namespace, min_depth} entries. Optional. See L2-7 below.

composes_with_reflections (L2-7)

Landed in v0.7.0 (L2-7, commit 0966b57, issue #672).

A skill declares which reflection namespaces it should be composed with at activation time via the composes_with_reflections frontmatter list. Each entry pins a namespace and a min_depth floor:

The substrate filters out reflections shallower than the per-entry min_depth, then applies the per-namespace GovernancePolicy::effective_max_reflection_depth as the authoritative ceiling: composition cannot bypass the bounded- recursion guarantee. Composition is a filter, not an override.

The list is round-trip-stable through JSON: registration parses it out of the YAML, embeds it under metadata.composes_with_reflections (so older clients that don’t know the field still see it as opaque metadata per the v0.7.0 backward-compat guarantee), and memory_skill_compositional_context reads it back. v0.9.0 promotes this declaration to a first-class composition manifest (cross-skill linkage + verifier tooling) — the field name, type, and semantics carry forward across that promotion.

Round-trip semantics

The substrate guarantees a content-addressed round-trip identity between registration, export, and re-registration:

register(folder_A) → skill_X with digest D
export(skill_X, folder_B)
register(folder_B) → skill_Y with digest D   (identical SHA-256)

The digest is over the canonical serialisation of the manifest plus the canonicalised resource payloads. Every field is stable across emit/parse cycles; resource order is normalised; whitespace is preserved verbatim. The guarantee survives transport across hosts, across operating systems, and across the v0.7.0 → v0.8.0 schema revisions documented in docs/MIGRATION_v0.7.md.

memory_skill_export appends one skill.exported row to the append-only signed_events audit table on every export, so a downstream auditor can re-derive when and by whom a skill was moved off the substrate.

Cross-node interchange (export-folder round-trip)

At v0.7.0 the federation receive pipeline (src/federation/receive.rs) ferries memories and memory_links between peers — it does not carry the skills / skill_resources tables. The canonical cross-node interchange shape for a skill is the export folder: memory_skill_export on node A produces SKILL.md + resources/, the operator ships the folder (e.g. tar | curl | tar -x), and memory_skill_register on node B consumes it. Because the digest is content-addressed over the canonical serialisation, node B’s registered row carries the identical SHA-256 digest — pinned end-to-end by tests/cov_17_skills_federation_roundtrip.rs.

On the receiving node:

A wire-level federation fanout for skills rides on this folder contract and is a future-release surface.

Ed25519 attestation

Every skills row is signable. When the daemon has a signing keypair on disk (under the key directory — AI_MEMORY_KEY_DIR, default platform config dir + /ai-memory/keys, layout <key_dir>/<agent_id>.{pub,priv}src/identity/keypair.rs), the registrar:

  1. Computes the canonical-byte digest of the manifest + resources.
  2. Signs the digest with the signing agent’s Ed25519 private key.
  3. Writes the signature plus the signing agent identity into the row; the companion signed_events row carries attest_level = "self_signed" (crate::models::AttestLevel::SelfSigned).

Unsigned skills (no keypair on disk, or an import with no inbound signature) carry attest_level = "unsigned" and the signature column is empty — verification surfaces this honestly rather than silently passing.

Verification on read is always-on: memory_skill_resource re-derives the resource’s SHA-256 digest and compares to the recorded value before returning the decompressed bytes. Mismatch is an error, never a quiet fallback.

The skill-level signature complements (does not replace) the forensic-bundle attestation described in forensic-export.md. A skill embedded in a forensic bundle gets re-attested at the bundle level too so the bundle itself is verifiable end-to-end.

Operator references

Forward roadmap