Skip to content

Release history

Skillscript releases

All releases

110 shown

No immediate action
v0.38.0 Breaking risk

New pipe filters: head, tail, lines, pluck

No immediate action
v0.37.0 Breaking risk

Timeout advisory + cancellation

Upgrade now
v0.36.1 Bug fix

Fixes ${VAR} delivery bug

Config change
v0.36.0 New feature
Breaking upgrade

Supervisor push notifications

Config change
v0.35.0 New feature
Breaking upgrade

Deadline enforcement + cancellation

Review required
v0.34.0 Security relevant
Auth

Shell secret scrubbing

No immediate action
v0.33.0 Breaking risk

Optional skill tags

No immediate action
v0.32.0 New feature

Mutation highlighting + plain‑language conditions

No immediate action
v0.31.1 Breaking risk

Skill description fix + docs clarification

No immediate action
v0.31.0 Breaking risk

Dark mode + diagram + scroll fix

No immediate action
v0.30.0 Breaking risk

Breaking changes — review before upgrading.

No immediate action
v0.27.3 Breaking risk

Dashboard render fix + docs update

No immediate action
v0.27.2 Breaking risk

Deprecated #OnError + recursion docs

No immediate action
v0.27.1 Breaking risk

Example compilation fixes

No immediate action
v0.27.0 New feature

Fallbacks catch all op failures

No immediate action
v0.26.6 Bug fix

Error‑handling clarification

No immediate action
v0.26.5 New feature

Error‑handling help topic

Review required
v0.26.4 New feature

Lint for unsafe append

No immediate action
v0.26.3 Bug fix

foreach zero‑iteration fix

Review required
v0.26.2 Bug fix

foreach + fallback fixes

No immediate action
v0.26.1 New feature

fsExecution allowlist

No immediate action
v0.26.0 New feature

Base64 file_read option

Config change
v0.25.3 Breaking risk
Auth

Data‑borne secret resolution blocked

Review required
v0.25.2 Bug fix
Auth

Fixes secret‑doc false positive

No immediate action
v0.25.1 Bug fix

Secret marker linting improvement

Config change
v0.25.0 New feature
Auth

Secret referencing in skills

No immediate action
v0.24.0 New feature

bootstrapFromEnv + version token

Upgrade now
v0.23.1 Bug fix

Self‑healing connector + advisory fix

Review required
v0.23.0 New feature
Auth RBAC

Connector schema retention

Config change
v0.22.1 Breaking risk
Auth

Escalation in allowlist denials

Review required
v0.22.0 New feature
Auth Breaking upgrade

Skill deletion for operators

No immediate action
v0.21.2 Bug fix

Dashboard approval fix

No immediate action
v0.21.1 New feature

`initialize` instructions

Review required
v0.21.0 Breaking risk
Auth

`skill_preflight` rename + security hardening

Config change
v0.20.2 New feature
Auth Breaking upgrade

Session‑bound click‑to‑approve

Config change
v0.20.1 New feature
Auth

Legacy skill migration + secured-mode warning

Review required
v0.20.0 Breaking risk
Auth RBAC

Enforced execution boundary + signing

No immediate action
v0.19.16 Breaking risk

MCP schema fix + trigger test

No immediate action
v0.19.15 New feature

58 execution tests

No immediate action
v0.19.14 New feature

Connectors section added

No immediate action
v0.19.13 Breaking risk

Removed Connectors & Use when

Review required
v0.19.12 Bug fix
Auth RCE / SSRF

Shell allowlist reporting + fallback fixes

Review required
v0.19.11 New feature
RCE / SSRF Breaking upgrade

Safe argv form + mutex + lint

Review required
v0.19.10 Breaking risk
Auth Breaking upgrade

Lint + outputs.text change

Config change
v0.19.9 Breaking risk
Auth Breaking upgrade

Parse error for allowed_tools

No immediate action
v0.19.8 Breaking risk

Template positioning flexibility

Review required
v0.19.7 Breaking risk
Breaking upgrade

Parser error on orphan ops + missing entry target

No immediate action
v0.19.6 Bugfix

Regression test fix

No immediate action
v0.19.4 New feature

Declarative output template

Review required
v0.19.3 New feature
Auth RBAC

SPA rendering tests

Upgrade now
v0.19.2 Breaking risk

Removed JS syntax errors

Review required
v0.19.1 Breaking risk
Auth RBAC

Runtime config resolver + trigger registration

v0.19.0 Breaking risk
⚠ Upgrade required
  • Run `skillfile lint` pre‑upgrade to locate skills using removed trigger sources.
  • Consult `docs/adopter-playbook.md` § "Trigger model" for migration patterns (POST to `/event`).
  • Update skill declarations: replace removed source types with an external adapter that POSTs to `/event`.
Breaking changes
  • Removed trigger source axis: dropped `session`, `agent-event`, `file-watch`, and `sensor` – only `cron` and `event` remain.
  • DeliveryMeta enum entry `trigger_kind: "session"` removed.
  • `scheduler.fireSessionPhase` API removed.
Notable features
  • `event_name` trigger primitive (case‑insensitive) for declarative event handling
  • `POST /event` HTTP ingress on DashboardServer, configurable via env vars and optional bearer‑token auth
  • Strict param validation per Perry's spec – every declared param must be present with no unknown params
Full changelog

Closes the locked Scott + Perry decision (memory ceaf4579): collapse
triggers to two primitives. Time-based (cron) + external-signal
(event via HTTP POST). Everything else is an external adapter that
POSTs to /event.

BREAKING

Trigger source axis trimmed. Pre-v0.19.0 the runtime accepted 6
sources (cron / session / event / agent-event / file-watch /
sensor); 4 of those were parse-only stubs that never functionally
fired. v0.19.0 keeps only cron and event. Skills declaring removed
sources fail to parse with a tier-1 parse error.

Migration: run skillfile lint against your corpus pre-upgrade to
find skills with removed sources. Each removed source has a
documented replacement pattern (external adapter POSTs to /event) —
see docs/adopter-playbook.md § "Trigger model".

DeliveryMeta trigger_kind: "session" removed from the enum. The
v0.9.6-locked receiver contract drops "session" from
origin.trigger_kind. Per Scott's call: the value was a non-feature
(session triggers never functionally emitted), and pre-v1.0 makes the
cleanup cheap. Adopter substrates handling DeliveryMeta payloads with
literal "session" trigger_kind will get a TypeScript narrowing error
on rebuild — drop the dead case.

scheduler.fireSessionPhase removed. Boot/shutdown session
dispatch is gone. Adopters wanting boot-time orchestration POST to
/event from their startup script.

New surfaces

event_name trigger primitive. Skills declare event triggers via
# Triggers: event: <event_name> (case-insensitive). External
posters address the event_name (the public contract); the
skill_name is private impl. 1:1 — exactly one skill per
event_name; cross-skill rebind allowed but audit-logged
(event_name 'X' rebound: skill A → skill B). Same-skill re-register
is silent upsert (declarative re-save path).

POST /event HTTP ingress on DashboardServer. Off by default
(SKILLSCRIPT_EVENT_INGRESS_ENABLED=true to opt in). Shares the
dashboard port — no separate port. Localhost-only by default; explicit
opt-in for 0.0.0.0. Optional bearer-token auth via
SKILLSCRIPT_EVENT_INGRESS_AUTH_TOKEN. Wire contract:

POST /event HTTP/1.1
Authorization: Bearer <token>   # if configured
Content-Type: application/json

{ "event_name": "ping", "params": { "NAME": "world" } }

→ 200 { "run_id": "<uuid>", "durability": "in-process" }
  404 unknown event_name | route disabled
  400 missing/extra params | malformed body
  401 missing/wrong auth
  405 wrong HTTP method

Strict param validation (v1): every declared param must be
present; no unknown params accepted. Per Perry's spec: no defaults,
no type coercion in v1 (JSON carries types; type mismatches fail
inside consuming ops with real errors). Defaults + types deferred to
v2 if real adopter need surfaces. Params are auto-derived from the
skill's # Vars: declaration for event triggers.

run_id = trace_id (preMintedTraceId plumbed through). The
synchronous run_id in the 200 response matches the trace_id the
runtime writes to the trace store — paste run_id into the dashboard
or query via the trace store to look up completion status.

Self-describing durability: every successful response includes
durability: "in-process". Honest contract: 200 = accepted into
THIS process's in-memory queue; best-effort / at-most-once / NOT
durable across restart. Durable queueing is a v2 follow-up.

Operator surfaces

Two new env vars (config-cascade-aware per existing pattern):

| Env var | Effect | Default |
|---|---|---|
| SKILLSCRIPT_EVENT_INGRESS_ENABLED=true | Mount POST /event route | false |
| SKILLSCRIPT_EVENT_INGRESS_AUTH_TOKEN=<token> | Bearer-token auth (when set, required on every POST) | unset (open-internally) |

Tests

21 new tests in v0.19.0-trigger-event-ring.test.ts:

  • Scheduler.fireEvent (6): happy + 404 + case-insensitive + missing + extra + no-params
  • Registration (2): same-skill silent upsert + cross-skill audit log
  • POST /event HTTP (11): disabled-404, GET-405, 200-with-run_id-durability, unknown-404, missing-400, extra-400, malformed-400, empty-event_name-400, 401-no-auth, 401-wrong-token, 200-correct-token
  • Config validation (1): throws if enabled without scheduler
  • MCP register_trigger (1): cron + event accepted

Plus 4 existing test files updated to v0.19.0 enum (cron+event only) +
new parse-error tests for removed sources. 1791 tests total; typecheck
clean.

Live HTTP probe verified end-to-end

Built dist, ran skillfile serve with event ingress enabled, POSTed
real curl requests:

  • Valid POST → 200 + run_id matching the trace file written to disk
  • 404 / 400 / 401 responses all match the spec
  • run_id f3495f73-... written to traces/event-probe/f3495f73-....json

Probe caught two gaps the unit tests didn't surface:

  • Event triggers needed params auto-derived from skill # Vars:
    (declarative wiring path)
  • dispatchSkill needed to thread event params into compile-time
    inputs (required-var check fired pre-execute)

Both fixed in the same ring; banking-worthy reminder of "build + probe
end-to-end before claiming done" discipline.

Docs

  • docs/adopter-playbook.md — new "Trigger model (v0.19.0 — BREAKING)"
    section: removed-source migration patterns + event primitive shape
    • wire contract + event_name semantics + enabling + durability
      honesty
  • docs/configuration.md — env-var table extended with
    SKILLSCRIPT_EVENT_INGRESS_*
  • scaffold/.env.example — new "Event-trigger HTTP ingress" section;
    clarifies SKILLSCRIPT_PORT is shared with the dashboard
  • README.md — MCP tool surface mentions POST /event opt-in

Language-reference rewrite is Perry's atom (forward-banner in place
since 05f24be0); landed when the v0.19.0 ring shipped clean.

What's NOT in v0.19.0 (future / deferred)

  • File-watch / sensor reference adapter stubs — scope-cut per Scott's
    call (memory b9fd8e17). Replaced by canonical "calling /event"
    example in Perry's upcoming language-reference rewrite.
  • Param defaults + type validation — deferred to v2 per Perry's spec.
  • Durable / at-least-once event queue — v2 if real adopter need
    surfaces; in-memory v1 self-describes via durability field.
  • c7ddfc50 body-text-as-output template ring — design-locked, queued
    for v0.19.1+ after trigger ring stabilizes.

Review required
v0.18.9 Mixed
Auth RBAC

Security dashboard + highlighting + bootstrap env

Config change
v0.18.8 Breaking risk
RBAC Breaking upgrade

Shell default-deny with allowlist

Config change
v0.18.7 New feature

Runtime knobs via ENV

No immediate action
v0.18.6 New feature

author field + filter

No immediate action
v0.18.5 Breaking risk

@session address‑routing

Review required
v0.18.4 Bug fix
Auth Breaking upgrade

Caller attribution fix

No immediate action
v0.18.3 Maintenance

AgentConnector documentation update

No immediate action
v0.18.1 New feature

AgentConnector parity

Review required
v0.18.2 Breaking risk
Auth Breaking upgrade

WakeReceipt honesty + session targeting

No immediate action
v0.18.0 New feature

Inline composition expansion

Review required
v0.17.5 Breaking risk
Auth RBAC

Top-level declared returns + name guard

Config change
v0.17.4 Mixed
Auth

Lint + env cascade + .env loader

Review required
v0.17.3 Breaking risk
Auth RBAC

Returns declaration filters final_vars

No immediate action
v0.17.2 Bug fix

Quote stripping fix

No immediate action
v0.17.1 Maintenance

Routine maintenance and dependency updates.

Config change
v0.17.0 New feature
Auth Breaking upgrade

Agent identity threading for skill authoring

Review required
v0.16.9 New feature
Auth RBAC

Identity‑propagation level 2 + store status preservation

Review required
v0.16.8 Breaking risk
Auth

Author capture + HttpMcpConnector honesty

No immediate action
v0.16.7 Bug fix

Triple-quote comma parsing fix

No immediate action
v0.16.6

Routine maintenance and dependency updates.

Review required
v0.16.5 New feature
Auth RBAC

HttpMcpConnector + Conformance + Kwarg lints

No immediate action
v0.16.4 New feature

Parse‑time model lint warning

Review required
v0.16.3 New feature
Auth RBAC

Manifest exposure in runtime_capabilities

Upgrade now
v0.16.2
Breaking upgrade

Routine maintenance and dependency updates.

Review required
v0.16.1 Breaking risk
Auth RCE / SSRF Dependencies

Audit findings closure

Review required
v0.16.0 Breaking risk
Breaking upgrade Auth

Dispatch discipline changes

Review required
v0.15.7 Bug fix

|json filter idempotent

No immediate action
v0.15.6 Maintenance

HTTP MCP documentation update

Review required
v0.15.5 Mixed
Auth RBAC

Expires_at null support + domain_tags fix

No immediate action
v0.15.4 Breaking risk

Idempotent roundtrip + warning suppressor

No immediate action
v0.15.3 New feature

Dashboard export + ESM flag

No immediate action
v0.15.2 Breaking risk

Canonical name arg in execute_skill

No immediate action
v0.15.1 Breaking risk

Init seeding + dashboard hint + SQLite warning suppression

Review required
v0.15.0 Breaking risk
Auth RBAC

In‑skill skill write/read bridge

Config change
v0.14.1 Breaking risk
Auth Breaking upgrade RBAC

Mutation enforcement + filter strictness

v0.14.0 Breaking risk
Breaking changes
  • `MemoryStore` → `DataStore` (contract name)
  • `MemoryStoreClass` → `DataStoreClass`
  • `MemoryStoreCapabilities` → `DataStoreCapabilities`
Full changelog

Pre-adoption window means breaking changes are still cheap. MemoryStore was
misleading nomenclature — it imported cognitive / agent-mental-state semantics
from AMP (the Tradita-internal substrate where this code originated) into what
is actually a generic data-persistence contract. Adopters without an AMP-like
memory broker had to mentally translate every time. Cost compounds per adopter;
pay once now.

The mental model after rename:

| Contract | What it does | Adopter intuition |
|---|---|---|
| SkillStore | Named, versioned, lifecycle-tracked code artifacts | "My skill catalog / code repo / playbook library" |
| DataStore | Generic key/value persistence with query | "My data store / KV store / search index" |
| Richer semantics (vector retrieval, memory broker, etc.) | Wire via MCP, not via skillscript contract | "Bring my own substrate" |

Both contracts describe what they DO. The asymmetry we documented in v0.13.8
(SkillStore is mutable/versioned CRUD vs append-only search log) is now
obvious-from-the-name, not a design stance the doc has to call out.

Breaking changes (every external identifier renamed; hard rename, no aliases)

Contract + types:

  • MemoryStoreDataStore
  • MemoryStoreClassDataStoreClass
  • MemoryStoreCapabilitiesDataStoreCapabilities
  • MemoryStoreManifestDataStoreManifest
  • MemoryStoreFeatureDataStoreFeature
  • MemoryWriteDataWrite
  • MemoryWriteRecordDataWriteRecord
  • PortableMemoryPortableData
  • CuratedMemoryFieldCuratedDataField
  • CURATED_MEMORY_FIELDSCURATED_DATA_FIELDS

Bundled impls + bridges + templates:

  • SqliteMemoryStoreSqliteDataStore
  • MemoryStoreMcpConnectorDataStoreMcpConnector
  • MemoryStoreTemplate (fork-me skeleton) → DataStoreTemplate

Registry methods:

  • registerMemoryStoreregisterDataStore
  • getMemoryStoregetDataStore
  • getMemoryStoreClassgetDataStoreClass
  • listMemoryStoreslistDataStores
  • listMemoryStoreClasseslistDataStoreClasses
  • hasMemoryStorehasDataStore

Config + env + filesystem:

  • connectors.json substrate key: memory_storedata_store
  • Env var: MEMORY_DBDATA_DB
  • Bootstrap option: memoryDbPathdataDbPath
  • Default db filename: <SKILLSCRIPT_HOME>/memory.db<SKILLSCRIPT_HOME>/data.db
  • runtime_capabilities field: memoryStoresdataStores

Ops (skill source) + MCP tools:

  • $ memory ... read op → $ data_read ...
  • $ memory_write ... write op → $ data_write ...
  • MCP tool: memory_readdata_read
  • Internally-registered MCP connector instance names: memorydata_read,
    memory_writedata_write

Source files:

  • src/connectors/memory-store.tsdata-store.ts
  • src/connectors/memory-store-mcp.tsdata-store-mcp.ts
  • examples/connectors/MemoryStoreTemplate/DataStoreTemplate/
  • examples/onboarding-scaffold/file-memory-store.tsfile-data-store.ts

NOT renamed (intentional — naming is honest)

  • SkillStore (and SqliteSkillStore, FilesystemSkillStore, etc.) — skills
    ARE skills. The misleading-naming pattern was specific to memory-store
    importing agent-cognition semantics into generic data persistence.
  • AgentConnector (and the HTTP webhook bridge) — substrate-neutral delivery
    to a frontier agent; name honestly describes the function.
  • docs/sqlite-skill-store.md filename — documents SqliteSkillStore which
    stays named. (Perry's initial rename mapping had this as a typo; corrected.)
  • language-reference.md rename pass — separate doc lane, Perry's work.

Adopter migration

This is a one-PR rename for any adopter who's forked a connector template. The
patterns are mechanical: every Memory identifier in your code becomes Data;
every $ memory op in your skills becomes $ data_read; every
registerMemoryStore call becomes registerDataStore; etc.

The Phase 2/3 cold-adopter AmpMemoryStore becomes AmpDataStore in the same
fashion. ~5 LOC of identifier renames per file plus the constructor/import
updates.

Why now

[[project_pre_adoption_rule]]: pre-adoption window is cheap; aliases + soft
deprecation are more total cost than one painful PR. SkillStore + DataStore is
the mental model we'd want a v1.0 reader to see immediately. Pay once now.

Review required
v0.13.8 New feature
Auth RBAC

memory_read + MemoryStore

Upgrade now
v0.13.7 Mixed
Auth Breaking upgrade

Skill corruption + template compilation

No immediate action
v0.13.6 Bug fix

Docs fixes + env var guidance

No immediate action
v0.13.5 Breaking risk

Build script split

No immediate action
v0.13.2 Breaking risk

YouTrack test removal

No immediate action
v0.10.0 Breaking risk

SqliteSkillStore default + Ollama removal

Upgrade now
v0.9.9 Bug fix
Auth Breaking upgrade

Fix derivation classification

v0.9.8 Breaking risk
⚠ Upgrade required
  • Update any code that consumes the flat `SkillMeta[]` array from `skill_list` to handle the new `SkillCatalog` shape.
  • Adjust dashboard components (e.g., bundled UI) to flatten the grouped response for table display if still required.
Breaking changes
  • Changed `skill_list` response from `SkillMeta[]` (flat array) to `SkillCatalog` object with `receives`, `skills`, and `headless` properties.
Notable features
  • Added category derivation logic for `augmenting`, `template`, and `headless` skill types based on output kinds.
  • Introduced `SkillListFilter` interface supporting AND-composed audience, status, trigger_kind, domain_tags, and name_prefix filters.
  • Implemented vars rendering rules converting frontmatter syntax (`NAME`, `NAME=value`, `NAME=`) into structured `{name, required, default}` entries.
Full changelog

Per Perry's audit thread f0b8b832 + addendum 73c79a28 + lock 011feaf0.
skill_list returns a pre-grouped SkillCatalog so cold agents reading at
session start see immediately "what pushes to me" vs "what I can invoke."

Wire shape changes (BREAKING — pre-adoption rule)

skill_list response shape changed from SkillMeta[] (flat array) to
SkillCatalog (pre-grouped object):

interface SkillCatalog {
  receives?: SkillEntry[];   // augmenting (# Output: agent:)
  skills?: SkillEntry[];     // template (# Output: template:) + agent-invokable
  headless?: SkillEntry[];   // no agent/template output; present when audience filter allows
}

interface SkillEntry {
  name: string;
  category: "augmenting" | "template" | "headless";
  description: string;
  status: SkillStatus;
  vars: Array<{ name: string; required: boolean; default: string | null }>;
  output: Array<{ kind: "agent" | "template" | "text" | "file" | "none"; target?: string }>;
  triggers: Array<
    | { kind: "cron"; expression: string }
    | { kind: "session"; phase: "start" | "end" }
    | { kind: "webhook"; path?: string }
    | { kind: "event"; event_type: string }
  >;
}

Category derivation

From existing # Output: semantics — no new frontmatter syntax. Multi-output rule:

ANY output[i].kind === "agent"    → "augmenting" (surfaces in `receives`)
else ANY output[i].kind === "template" → "template" (surfaces in `skills`)
else                              → "headless"   (surfaces only when audience filter allows)

Filter mechanism (AND-composed)

interface SkillListFilter {
  audience?: "agent" | "all" | "headless";  // default "agent"
  status?: SkillStatus;                      // default "Approved"
  trigger_kind?: "cron" | "session" | "webhook" | "event";
  domain_tags?: string[];                    // AND-match
  name_prefix?: string;                      // adopter-side scoping
}

Vars rendering (per addendum 73c79a28)

| # Vars: frontmatter | Rendered entry |
|---|---|
| NAME (bare) | { name: "NAME", required: true, default: null } |
| NAME=value | { name: "NAME", required: false, default: "value" } |
| NAME= (equals, empty value) | { name: "NAME", required: false, default: "" } |

Footnote pinned in SkillEntry doc-comment

"Invocation is independent of discovery grouping. execute_skill(skill_name="X")
works regardless of whether X surfaced in receives or skills. Discovery
grouping is signal, not gating."

Added

  • src/skill-catalog.tsbuildSkillCatalog() + category derivation +
    vars/outputs/triggers rendering helpers (~160 LOC; auxiliary surface, not narrow-core)
  • src/connectors/types.tsSkillCatalog, SkillEntry, SkillListFilter interfaces
  • tests/v0.9.8-skill-catalog.test.ts — locked-shape coverage (category derivation,
    vars rendering, triggers union, filter composition, audience grouping, Q2 footnote)

Migration

  • mcp__skillscript__skill_list callers consuming the flat-array shape break.
    Pre-adoption rule applies; no shipped adopters.
  • Bundled dashboard updated to flatten the grouped response for its existing
    table view.

LOC ceiling

Bumped narrow-core 8550 → 8650 for the new contract types in connectors/types.ts.
Fourth bump in v0.9.x; consolidate-first signal stands but new contract surface
isn't consolidatable.

No immediate action
v0.9.7 New feature

HttpWebhookAgentConnector example

Config change
v0.9.6 Breaking risk
Breaking upgrade

Connector contract lock

No immediate action
v0.9.5 Breaking risk

Lint fixes reduce false positives

Review required
v0.8.0 Breaking risk
Auth Breaking upgrade

OutputKind rename + notify + memory_write

Review required
v0.7.3 Breaking risk
Auth Breaking upgrade

OutputKind cleanup + new APIs

v0.7.2 Breaking risk
⚠ Upgrade required
  • Update skills using literal backslash sequences (`\n`, `\t`) in double‑quoted strings to match new escape semantics.
  • Lints now suggest `$ llm` and `$ memory` for deprecated symbol ops; adjust remediation messages accordingly.
Breaking changes
  • String escape interpretation in double‑quoted strings changes behavior (\n, \t, \\, \" now produce actual characters) — pre‑adoption rule applies; existing skills using literal \n bytes must be rewritten.
Notable features
  • Triple‑quote multi‑line string literals (`"""...""") for prose‑shaped content.
  • `${VAR}` substitution in `# Output:` target slot enabling compile‑time input resolution.
  • Bridge classes: `LocalModelMcpConnector`, `MemoryStoreMcpConnector` with auto‑wire at bootstrap.
Full changelog

R4-driven punchlist + bridge classes. Closes the cold-author findings
from the R4 harness round (Perry's report d284763f, Scott's decisions
d89905f3, bridge-class scope-lock 831c2661, Perry's GO 5f471b0a).
The hypothesis test passed in R4 — minions reached for canonical
emit(), file_write(), ${VAR} naturally; friction moved deeper into
substantive language semantics. v0.7.2 closes the substantive friction
and lands the substrate-portability story end-to-end.

Added — language semantics

  • String escape interpretation in double-quoted strings. \n, \t,
    \\, \" interpret to their actual chars inside "...". Bash /
    Python / JS / Go / C all do this; skillscript joins the prior. R4
    minion 4 was reaching for @ printf %b "${VAR}" as a workaround;
    now $set X = "line1\nline2" produces real newlines. Single-quoted
    strings stay literal pass-through (reserved for v0.8+ literal
    semantics). Breaking change — pre-adoption rule applies (no
    external users to disrupt); any skill relying on literal \n bytes
    needs a one-time rewrite.

  • Triple-quote multi-line string literals. """...""" for prose-
    shaped content. Spans line breaks naturally; embedded single "
    doesn't terminate (three consecutive " chars don't accidentally
    appear in natural English). Escape interpretation applies same as
    single double-quote. Use cases: long-form emit(text="""..."""),
    file_write(content="""..."""), multi-line $set X = """..."""
    reports.

  • ${VAR} substitution in # Output: target slot. Compile-time
    inputs resolution (caller-passed inputs to compile_skill,
    # Vars: defaults, # Requires: cascade values). Runtime-bound
    refs (from $ op outputs) explicitly deferred — needs two-phase
    frontmatter resolution architectural call. Closes R4 finding #6
    (minion 5 wrote # Output: prompt-context: ${TARGET_AGENT} expecting
    parameterized routing; now works).

Added — lints

  • Tier-3 object-iteration-advisory lint. R4's strongest signal
    (4 of 5 minions hit it). Fires on foreach IT in ${VAR} where VAR's
    binding origin is a $ MCP tool output without .field accessor.
    Hints at common envelope-field names (.items, .results,
    .issuesPage, .data, .records). Placeholder for v0.8 tool-schema
    introspection that catches this precisely.

  • unconfirmed-mutation broadened to legacy @ ops. Closes R4
    minion 4 sub-finding: @ printf %b ${REPORT} silently word-split
    when REPORT contained whitespace. Lint now flags any suspect
    ${VAR} substitution in @ op bodies (same origin-detection logic
    as the existing $ op coverage). Pattern also widened to recognize
    both $(VAR) and ${VAR} forms.

Added — bridge classes (substrate-portability lands)

  • LocalModelMcpConnector. Bridge class that exposes a registered
    LocalModel instance as an McpConnector. Wraps LocalModel.run
    per the canonical contract:
    $ <connector> prompt="..." [maxTokens=N] [model="..."] -> R where
    R is the model's response string.

  • MemoryStoreMcpConnector. Bridge class that exposes a registered
    MemoryStore instance as an McpConnector. Wraps MemoryStore.query:
    $ <connector> mode="fts|semantic|rerank" query="..." limit=N [...extras] -> R where R = {items: PortableMemory[]} envelope
    (consistent with the object-iteration-advisory's hint pattern).

  • Bootstrap auto-wire. Bridges wire automatically at bootstrap as
    connector instances llm (default LocalModel) + memory (default
    MemoryStore, when SQLite db exists). Zero-config — $ llm prompt="..."
    and $ memory mode=fts query="..." limit=10 work in default
    deployments without adopter wiring. Adopters override by re-registering
    the names or wiring entries in connectors.json.

Architectural framing — canonical MCP-dispatch contract

v0.7.2 doesn't just ship bridge code — it defines what $ llm and
$ memory MEAN in skillscript
by shipping with explicit kwarg surfaces.

Two layers of substrate portability:

  1. LocalModel + MemoryStore interface contracts (typed contracts
    within the runtime). Adopters implement these to plug in their
    substrate without writing MCP servers. Bundled OllamaLocalModel +
    SqliteMemoryStore are reference impls.
  2. MCP dispatch via $ <name> — bridge classes expose Layer 1 as
    MCP; adopters can also bypass bridges and wire any MCP server under
    any name ($ pinecone_vector, $ amp.amp_query_memories, etc.).

Bundled memory surface is ONE canonical call (per Perry's scope-lock
5f471b0a):

$ memory mode="fts|semantic|rerank" query="..." limit=N [...extras] -> R

Read-only, FTS-flavored. Substrate-portable across any MemoryStore-
interface impl. Explicitly not bundled (adopter wires via dotted-form
escape hatch $ <connector>.<tool>):

  • $ memory_write, $ memory_get (no MemoryStore interface methods)
  • Thread operations ($ thread_get, $ thread_close,
    $ thread_check_mailbox, etc.) — substrate-specific
  • Introspection / traversal / promote / reinforce — substrate-specific
  • Mutations beyond write — substrate-specific

For Tradita-style deployments, AMP wires as $ amp.<tool> with the
full ~15-tool surface available; $ memory covers the canonical query
path, $ amp.<tool> covers AMP-specific operations.

Changed

  • deprecated-symbol-op lint — remediation messages now confidently
    suggest $ llm / $ memory (the bridge auto-wire makes these
    load-bearing in default deployments). No more "(or your wired LLM
    connector name)" caveat.

  • help() content — all six topics (quickstart, ops, frontmatter,
    examples, composition, connectors, lint-codes) refreshed to canonical
    v0.7.0+ surface. Container FS isolation note added. object-iteration- advisory indexed. Tradita-internal naming scrubbed from connectors
    topic.

  • Quickstart hero example — broken $append REPORT <line>...</line>
    accumulator pattern replaced with emit(text="...") per-line +
    # Output: prompt-context: delivery channel. Matches Perry's
    corrected §1 doc atom.

  • AST: op.sourceForm?: "function-call" field already added in v0.7.1
    to distinguish canonical from legacy at lint time. Continues to do
    load-bearing work for the deprecated-symbol-op lint.

LOC ceiling

Narrow-core ceiling 7250 → 7550. Bridges add ~80 LOC each (auxiliary
surface). String-escape interpreter + triple-quote tokenizer state +
${VAR}-in-Output substitution + object-iteration advisory + @-op
unquoted-subst extension add ~200 LOC narrow-core total.

Tests

53 new tests across 5 v0.7.2-specific test files:

  • v0.7.2-object-iteration-advisory.test.ts — 6 tests
  • v0.7.2-string-escapes.test.ts — 12 tests
  • v0.7.2-triple-quote-literals.test.ts — 14 tests
  • v0.7.2-output-substitution.test.ts — 9 tests
  • v0.7.2-unquoted-subst-at-op.test.ts — 7 tests
  • v0.7.2-bridge-classes.test.ts — 16 tests (unit + closed-set registry)

Plus updated fixtures across test files where bootstrap auto-wire
shifted expected behavior. Suite: 974 passing, 10 skipped, 1 env-gated
YouTrack.

Deferred to v0.8 (per locked roadmap)

  • Tool-schema introspection that adapts the object-iteration-advisory
    • deprecation lints based on actual connector availability
  • Richer memory contract covering vector / embedding / hybrid
    substrates beyond FTS-flavored query
  • MemoryStore.write() interface addition to enable a bundled
    $ memory_write bridge (currently adopter-wired)
  • Pagination / while loop primitive (v0.9)
  • Phase 2 trigger sources (event + agent-event) — v0.11
  • Output routers (slack + card) — v0.12
Review required
v0.7.0 Breaking risk
RBAC RCE / SSRF

Breaking changes — review before upgrading.

Review required
v0.5.0 Breaking risk
Auth RBAC

NOW ISO‑8601, append type‑dispatch, connector error

No immediate action
v0.4.4 New feature

Full connector registry rendering

No immediate action
v0.4.3 New feature

Auto-discover connectors + --connectors flag

No immediate action
v0.4.2 New feature

Markdown extraction + autonomous header

Config change
v0.4.1 New feature
Auth RBAC

RemoteMcpConnector + config changes

Config change
v0.4.0 New feature
Auth

`connectors.json` loader + credentials

Beta — feedback welcome: [email protected]