skillscript-runtime 0.2.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (132) hide show
  1. package/ARCHITECTURE.md +70 -0
  2. package/LICENSE +21 -0
  3. package/README.md +346 -0
  4. package/dist/audit.d.ts +33 -0
  5. package/dist/audit.d.ts.map +1 -0
  6. package/dist/audit.js +76 -0
  7. package/dist/audit.js.map +1 -0
  8. package/dist/bootstrap.d.ts +69 -0
  9. package/dist/bootstrap.d.ts.map +1 -0
  10. package/dist/bootstrap.js +117 -0
  11. package/dist/bootstrap.js.map +1 -0
  12. package/dist/cli.d.ts +3 -0
  13. package/dist/cli.d.ts.map +1 -0
  14. package/dist/cli.js +805 -0
  15. package/dist/cli.js.map +1 -0
  16. package/dist/compile.d.ts +88 -0
  17. package/dist/compile.d.ts.map +1 -0
  18. package/dist/compile.js +544 -0
  19. package/dist/compile.js.map +1 -0
  20. package/dist/connectors/agent-noop.d.ts +23 -0
  21. package/dist/connectors/agent-noop.d.ts.map +1 -0
  22. package/dist/connectors/agent-noop.js +43 -0
  23. package/dist/connectors/agent-noop.js.map +1 -0
  24. package/dist/connectors/agent.d.ts +54 -0
  25. package/dist/connectors/agent.d.ts.map +1 -0
  26. package/dist/connectors/agent.js +21 -0
  27. package/dist/connectors/agent.js.map +1 -0
  28. package/dist/connectors/index.d.ts +13 -0
  29. package/dist/connectors/index.d.ts.map +1 -0
  30. package/dist/connectors/index.js +17 -0
  31. package/dist/connectors/index.js.map +1 -0
  32. package/dist/connectors/local-model.d.ts +41 -0
  33. package/dist/connectors/local-model.d.ts.map +1 -0
  34. package/dist/connectors/local-model.js +106 -0
  35. package/dist/connectors/local-model.js.map +1 -0
  36. package/dist/connectors/mcp.d.ts +22 -0
  37. package/dist/connectors/mcp.d.ts.map +1 -0
  38. package/dist/connectors/mcp.js +31 -0
  39. package/dist/connectors/mcp.js.map +1 -0
  40. package/dist/connectors/memory-store.d.ts +53 -0
  41. package/dist/connectors/memory-store.d.ts.map +1 -0
  42. package/dist/connectors/memory-store.js +169 -0
  43. package/dist/connectors/memory-store.js.map +1 -0
  44. package/dist/connectors/registry.d.ts +74 -0
  45. package/dist/connectors/registry.d.ts.map +1 -0
  46. package/dist/connectors/registry.js +127 -0
  47. package/dist/connectors/registry.js.map +1 -0
  48. package/dist/connectors/skill-store.d.ts +38 -0
  49. package/dist/connectors/skill-store.d.ts.map +1 -0
  50. package/dist/connectors/skill-store.js +314 -0
  51. package/dist/connectors/skill-store.js.map +1 -0
  52. package/dist/connectors/types.d.ts +188 -0
  53. package/dist/connectors/types.d.ts.map +1 -0
  54. package/dist/connectors/types.js +35 -0
  55. package/dist/connectors/types.js.map +1 -0
  56. package/dist/dashboard/server.d.ts +40 -0
  57. package/dist/dashboard/server.d.ts.map +1 -0
  58. package/dist/dashboard/server.js +122 -0
  59. package/dist/dashboard/server.js.map +1 -0
  60. package/dist/dashboard/spa/app.js +375 -0
  61. package/dist/dashboard/spa/index.html +26 -0
  62. package/dist/dashboard/spa/styles.css +99 -0
  63. package/dist/errors.d.ts +111 -0
  64. package/dist/errors.d.ts.map +1 -0
  65. package/dist/errors.js +187 -0
  66. package/dist/errors.js.map +1 -0
  67. package/dist/filters.d.ts +17 -0
  68. package/dist/filters.d.ts.map +1 -0
  69. package/dist/filters.js +40 -0
  70. package/dist/filters.js.map +1 -0
  71. package/dist/index.d.ts +41 -0
  72. package/dist/index.d.ts.map +1 -0
  73. package/dist/index.js +33 -0
  74. package/dist/index.js.map +1 -0
  75. package/dist/lint.d.ts +97 -0
  76. package/dist/lint.d.ts.map +1 -0
  77. package/dist/lint.js +990 -0
  78. package/dist/lint.js.map +1 -0
  79. package/dist/mcp-server.d.ts +93 -0
  80. package/dist/mcp-server.d.ts.map +1 -0
  81. package/dist/mcp-server.js +505 -0
  82. package/dist/mcp-server.js.map +1 -0
  83. package/dist/metrics.d.ts +51 -0
  84. package/dist/metrics.d.ts.map +1 -0
  85. package/dist/metrics.js +107 -0
  86. package/dist/metrics.js.map +1 -0
  87. package/dist/parser.d.ts +160 -0
  88. package/dist/parser.d.ts.map +1 -0
  89. package/dist/parser.js +991 -0
  90. package/dist/parser.js.map +1 -0
  91. package/dist/provenance.d.ts +43 -0
  92. package/dist/provenance.d.ts.map +1 -0
  93. package/dist/provenance.js +58 -0
  94. package/dist/provenance.js.map +1 -0
  95. package/dist/runtime.d.ts +145 -0
  96. package/dist/runtime.d.ts.map +1 -0
  97. package/dist/runtime.js +1071 -0
  98. package/dist/runtime.js.map +1 -0
  99. package/dist/scheduler.d.ts +121 -0
  100. package/dist/scheduler.d.ts.map +1 -0
  101. package/dist/scheduler.js +271 -0
  102. package/dist/scheduler.js.map +1 -0
  103. package/dist/skill-manager.d.ts +121 -0
  104. package/dist/skill-manager.d.ts.map +1 -0
  105. package/dist/skill-manager.js +251 -0
  106. package/dist/skill-manager.js.map +1 -0
  107. package/dist/testing/conformance.d.ts +57 -0
  108. package/dist/testing/conformance.d.ts.map +1 -0
  109. package/dist/testing/conformance.js +365 -0
  110. package/dist/testing/conformance.js.map +1 -0
  111. package/dist/testing/index.d.ts +3 -0
  112. package/dist/testing/index.d.ts.map +1 -0
  113. package/dist/testing/index.js +5 -0
  114. package/dist/testing/index.js.map +1 -0
  115. package/dist/trace.d.ts +141 -0
  116. package/dist/trace.d.ts.map +1 -0
  117. package/dist/trace.js +226 -0
  118. package/dist/trace.js.map +1 -0
  119. package/examples/README.md +56 -0
  120. package/examples/classify-support-ticket.skill.md +30 -0
  121. package/examples/cut-release-tag.skill.md +40 -0
  122. package/examples/doc-qa-with-citations.skill.md +12 -0
  123. package/examples/feedback-sentiment-scan.skill.md +29 -0
  124. package/examples/hello.skill.md +9 -0
  125. package/examples/hello.skill.provenance.json +10 -0
  126. package/examples/morning-brief.skill.md +24 -0
  127. package/examples/programmatic-trace-demo.mjs +89 -0
  128. package/examples/service-health-watch.skill.md +18 -0
  129. package/package.json +100 -0
  130. package/scaffold/config.toml +35 -0
  131. package/scaffold/connectors.json +19 -0
  132. package/scaffold/examples/hello.skill.md +9 -0
@@ -0,0 +1,70 @@
1
+ # Architecture
2
+
3
+ One-page map of the `skillscript-runtime` codebase. Per ERD §1, the core stays ≤ 5K LOC across < 20 source files. Tests count separately.
4
+
5
+ ## Top-level layout
6
+
7
+ ```
8
+ src/
9
+ index.ts — library entrypoint; named exports for embedders
10
+ cli.ts — `skillfile` CLI entrypoint
11
+ parser.ts — source text → AST
12
+ compile.ts — AST → resolved skill model → rendered artifact (owns toposort)
13
+ filters.ts — pipe-filter implementations (url / shell / json / trim)
14
+ lint.ts — structural validation (compiler preflight + standalone)
15
+ runtime.ts — executor: walks compiled artifact, dispatches ops
16
+ scheduler.ts — trigger registry + cron scan (T5)
17
+ output.ts — output dispatch (text, prompt-context, none) (T6/T7)
18
+ connectors/
19
+ types.ts — contracts: SkillStore, MemoryStore, LocalModel, McpConnector
20
+ registry.ts — per-kind instance registry + three-layer resolution
21
+ skill-store.ts — bundled default: filesystem at ~/.skillscript/skills/
22
+ memory-store.ts — bundled default: SQLite + FTS at ~/.skillscript/memory.db
23
+ local-model.ts — bundled default: Ollama at localhost:11434
24
+ mcp.ts — bundled default: stub; no servers wired by default
25
+ ```
26
+
27
+ Target: 13 source files written + 2 more planned (scheduler.ts in T5, output.ts in T6/T7). Budget headroom from the < 20 ceiling: 5 files.
28
+
29
+ ## What each file owns
30
+
31
+ | File | Responsibility |
32
+ | --- | --- |
33
+ | `parser.ts` | Tokenize and parse skill source. Header lines, target blocks, op grammar, conditionals, `foreach`, variable interpolation. Produces AST. Syntax errors only — semantic checks are downstream. |
34
+ | `compile.ts` | Three subsystems: (1) variable resolution against `# Requires:` cascade + caller inputs; (2) data-skill compile-time inlining (T3); (3) topo-sort + render. Owns the `toposort` function (semantic analysis). Output formats: `prompt` (canonical), `prose`, `test`. Produces compiled artifact + provenance. |
35
+ | `filters.ts` | Pipe-filter implementations dispatched by `$(NAME|filter)` syntax. v1: `url`, `shell`, `json`, `trim`. Adding a new filter = adding a case to `applyFilter` and documenting it in the Language Reference. Per ERD §2 modifiability, this is the predictable location agents look for filter extensions. |
36
+ | `lint.ts` | Structured diagnostics. T1 baseline rules: `parse-error` (any parser syntax error), `no-targets` (zero targets), `no-entry-target` (no `default:` resolved), `orphan-target` (target unreachable from entry). Full 20-rule v1 set + adversarial library land in T4 — baseline rules keep their IDs and severity through T4 so authors consuming today's diagnostics don't see breakage. |
37
+ | `runtime.ts` | Executor that walks the compiled artifact and dispatches ops through connector instances. Handles error propagation, per-op timeout chain, `foreach` iteration, conditionals, `$set`, output binding. |
38
+ | `scheduler.ts` | Trigger registry. Cron firing in v1; event/agent-event/file-watch/sensor are parse-only. Status-aware: skips `Draft` / `Disabled` skills at fire time. |
39
+ | `output.ts` | Routes the goal target's output by `# Output:` header. Kinds: `text` (stdout), `prompt-context` (returns to caller), `none`. |
40
+ | `connectors/types.ts` | The four contract interfaces. The integration boundary — every external system (skill storage, memory, local model, MCP) plugs in through one of these. |
41
+ | `connectors/registry.ts` | Maps connector names to instances. Three-layer resolution: per-call override > skill-declared > primary default. Multi-instance support. |
42
+ | `connectors/skill-store.ts` | Filesystem-backed `SkillStore`. Reads/writes skills as `*.skill.md` files under `~/.skillscript/skills/` (the `.skill` extension is reserved for compiled artifacts). Status transitions produce git-friendly file history. |
43
+ | `connectors/memory-store.ts` | SQLite-backed `MemoryStore` with FTS5. Schema: `memories(id, summary, detail, tags, created_at)`. PortableMemory shape + metadata bag. |
44
+ | `connectors/local-model.ts` | Ollama HTTP client. Bundled instances: `default` and `gemma2` (both `gemma2:9b`), `qwen` (`qwen2.5:7b`). |
45
+ | `connectors/mcp.ts` | MCP connector scaffold. v1: no servers wired by default; `connectors.json` has commented example. |
46
+
47
+ ## Non-source
48
+
49
+ ```
50
+ docs/ — spec documentation (PRD, Language Reference, ERD)
51
+ examples/ — bundled example skills (incl. `hello.skill.md`)
52
+ scaffold/ — files copied by `skillfile init` into ~/.skillscript/
53
+ scripts/loc-ceiling.mjs — CI check; fails if core exceeds budget
54
+ tests/ — vitest specs
55
+ .github/workflows/ — CI: tests + loc-ceiling on push/PR
56
+ Dockerfile — multi-arch image base
57
+ docker-compose.yml — runtime + Ollama + SQLite volume
58
+ ```
59
+
60
+ ## Out-of-scope for T1
61
+
62
+ Defers to later threads per the v1 plan:
63
+
64
+ - **T2** — full connector contract surface, capabilities discovery, identity propagation
65
+ - **T3** — data-skill inlining in `compile.ts` (T1 ports the existing simpler compile path)
66
+ - **T4** — 20-rule v1 lint set + adversarial library
67
+ - **T5** — autonomous trigger dispatch (T1 has parse-only `# Triggers:`)
68
+ - **T6** — browser dashboard
69
+ - **T7** — full CLI (`diagram`, `audit`, `sign`/`verify`, etc.), MCP server contract
70
+ - **T8** — backend-specific adapters for the four contracts
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Scott Shwarts
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,346 @@
1
+ # Skillscript
2
+
3
+ > A small declarative language for authoring agent workflows.
4
+
5
+ **Status: v1 in progress (current release: 0.2.4).** The public API, language syntax, and connector contracts may change before v1.0.0. Expect breakage until then.
6
+
7
+ A skillscript is a declarative recipe — a small program with a dependency DAG of named targets, each composed of typed operations. Skills are authored once and executed many times, either by the interpreter (autonomous, cron-fired) or by an agent reading a compiled prompt artifact.
8
+
9
+ The runtime is substrate-neutral. Bundled reference connectors back filesystem, SQLite, Ollama, and an MCP scaffold; adapter implementations against other backings (cloud key-value stores, hosted LLMs, vector DBs) live in separate packages that consume the public connector contracts exported here.
10
+
11
+ ---
12
+
13
+ ## Table of contents
14
+
15
+ 1. [Installation](#installation)
16
+ 2. [Quickstart: author and run a skill](#quickstart-author-and-run-a-skill)
17
+ 3. [CLI reference](#cli-reference)
18
+ 4. [Browser dashboard](#browser-dashboard)
19
+ 5. [Container deployment](#container-deployment)
20
+ 6. [Language overview](#language-overview)
21
+ 7. [Connector model](#connector-model)
22
+ 8. [External adapters](#external-adapters)
23
+ 9. [Library API](#library-api)
24
+ 10. [Contributing](#contributing)
25
+ 11. [License](#license)
26
+
27
+ ---
28
+
29
+ ## Installation
30
+
31
+ ### npm (recommended)
32
+
33
+ ```sh
34
+ npm install -g skillscript-runtime
35
+ skillfile --version
36
+ ```
37
+
38
+ This installs the `skillfile` binary globally. Requires Node.js ≥ 22.5 (the runtime uses `node:sqlite` and other features that landed in 22.5+).
39
+
40
+ ### From source
41
+
42
+ ```sh
43
+ git clone https://github.com/sshwarts/skillscript-runtime.git
44
+ cd skillscript-runtime
45
+ pnpm install
46
+ pnpm run build
47
+ node dist/cli.js --help
48
+ ```
49
+
50
+ The repo uses pnpm for reproducible installs. `pnpm run build` compiles TypeScript to `dist/` and copies dashboard assets into place.
51
+
52
+ ---
53
+
54
+ ## Quickstart: author and run a skill
55
+
56
+ ```sh
57
+ # 1. Scaffold the config tree
58
+ skillfile init
59
+
60
+ # 2. Inspect the bundled hello example
61
+ cat ~/.skillscript/examples/hello.skill.md
62
+
63
+ # 3. Run it (no Ollama, no MCP, no external state required)
64
+ skillfile run examples/hello.skill.md
65
+ # → Hello, world!
66
+
67
+ # 4. Override an input
68
+ skillfile run hello --input WHO=Scott
69
+ # → Hello, Scott!
70
+ ```
71
+
72
+ A minimal `.skill.md` looks like:
73
+
74
+ ```skillscript
75
+ # Skill: greet
76
+ # Status: Draft
77
+ # Vars: WHO=world
78
+
79
+ greet:
80
+ ! Hello, $(WHO)!
81
+
82
+ default: greet
83
+ ```
84
+
85
+ Save that as `greet.skill.md` and run `skillfile run ./greet.skill.md`. The `!` op emits a message; the dispatcher walks the dependency DAG from `default:` backward.
86
+
87
+ Lint as you go:
88
+
89
+ ```sh
90
+ skillfile lint ./greet.skill.md
91
+ ```
92
+
93
+ Compile to a prompt artifact (the form an agent consumes when it dispatches a skill mid-conversation):
94
+
95
+ ```sh
96
+ skillfile compile ./greet.skill.md
97
+ # Writes greet.skill.provenance.json sidecar with content hashes
98
+ ```
99
+
100
+ ---
101
+
102
+ ## CLI reference
103
+
104
+ All 13 commands. Run `skillfile <command> --help` for per-command options + examples.
105
+
106
+ | Command | Purpose |
107
+ |---|---|
108
+ | `init` | Scaffold `~/.skillscript/` tree + bundled example |
109
+ | `run <path\|name>` | Compile + execute a skill end-to-end |
110
+ | `compile <path\|name>` | Render the compiled artifact (no execution) |
111
+ | `audit <provenance-path>` | Detect recompile-staleness via `.provenance.json` sidecar |
112
+ | `lint <path\|name>` | Run static validation, print findings |
113
+ | `list` | List available skills in the configured SkillStore |
114
+ | `fires <skill>` | List recent trace records for a skill |
115
+ | `diagram <path\|name>` | Emit mermaid graph of the skill's control flow |
116
+ | `sign <path\|name>` | Content-hash sign the skill source (SHA-256) |
117
+ | `verify <path\|name> <hash>` | Verify the skill matches a signature |
118
+ | `replay <trace_id>` | Re-run a recorded trace mechanically |
119
+ | `health` | Aggregate runtime metrics across all traces |
120
+ | `dashboard` | Start the runtime host: scheduler + MCP server + browser dashboard SPA |
121
+
122
+ > Trigger registration is handled through the MCP server exposed by `skillfile dashboard` (`register_trigger` / `unregister_trigger` / `list_triggers` tools). The v0.2.0 CLI register-trigger family was removed in v0.2.1 — those commands constructed throwaway in-memory schedulers and never fired.
123
+
124
+ Environment variables:
125
+
126
+ | Var | Default | Purpose |
127
+ |---|---|---|
128
+ | `SKILLSCRIPT_HOME` | `~/.skillscript` | Config + data root |
129
+ | `OLLAMA_BASE_URL` | `http://localhost:11434` | Ollama endpoint for LocalModel dispatch |
130
+
131
+ ---
132
+
133
+ ## Browser dashboard
134
+
135
+ The runtime ships with a browser dashboard for non-CLI operators. Five views: overview, skills, triggers, connectors, plus a skill detail drilldown. 30-second polling; write paths for status transitions and trigger CRUD. Localhost-only by default — no authentication in v1.
136
+
137
+ ```sh
138
+ skillfile dashboard
139
+ # → http://127.0.0.1:7878
140
+ ```
141
+
142
+ Options:
143
+
144
+ ```sh
145
+ skillfile dashboard --port 8080 # custom port
146
+ skillfile dashboard --host 0.0.0.0 # bind all interfaces (container only)
147
+ ```
148
+
149
+ The dashboard talks to the runtime via an MCP server contract (JSON-RPC 2.0 over HTTP at `/rpc`). Real MCP clients (Claude Desktop, Cursor, future tools) can consume the same endpoint — the SPA is one of several possible UIs over the same contract. **Eleven tools** today: `skill_list`, `skill_metadata`, `skill_status` (write), `list_triggers`, `register_trigger` (write), `unregister_trigger` (write), `health_metrics`, `runtime_capabilities`, `lint_skill`, `compile_skill`, `skill_write` (write). The last three (v0.2.3) close the over-the-wire authoring lifecycle — foreign clients can lint → compile → write → status → register_trigger end-to-end without filesystem access.
150
+
151
+ ---
152
+
153
+ ## Container deployment
154
+
155
+ The repo ships a multi-stage Dockerfile + `docker-compose.yml`. The image bundles the runtime, CLI, and dashboard SPA in one Node process.
156
+
157
+ ```sh
158
+ docker compose up --build # default profile: dashboard
159
+ # → http://127.0.0.1:7878
160
+ ```
161
+
162
+ Profiles:
163
+
164
+ ```sh
165
+ docker compose --profile tools run --rm tools lint my-skill.skill.md
166
+ docker compose --profile ollama up # adds Ollama for LocalModel
167
+ ```
168
+
169
+ Persistent state (`SKILLSCRIPT_HOME=/data`) mounts as a volume so skills + traces survive restarts. The host port mapping (`127.0.0.1:7878:7878`) keeps the dashboard reachable only from localhost even though the container itself binds `0.0.0.0` internally.
170
+
171
+ ### Pulling from a registry
172
+
173
+ Images publish to GitHub Container Registry:
174
+
175
+ ```sh
176
+ docker pull ghcr.io/sshwarts/skillscript-runtime:latest
177
+ # or pin to a specific version
178
+ docker pull ghcr.io/sshwarts/skillscript-runtime:v0.2.4
179
+ ```
180
+
181
+ Authentication (`gh auth login` then `gh auth token | docker login ghcr.io -u sshwarts --password-stdin`) is only required for pushes; pulls are public.
182
+
183
+ ---
184
+
185
+ ## Language overview
186
+
187
+ A skill is markdown with structured headers and a body of named targets:
188
+
189
+ ```skillscript
190
+ # Skill: weather-brief
191
+ # Status: Approved
192
+ # Vars: CITY=Asheville
193
+ # Requires: user-var:home_location -> CITY (fallback: Asheville)
194
+ # Triggers: cron: */30 * * * *
195
+
196
+ fetch needs:
197
+ ~ memory-store.get key="weather:$(CITY|url)" -> CACHED
198
+
199
+ forecast: fetch
200
+ if $(CACHED):
201
+ $set FORECAST = $(CACHED)
202
+ else:
203
+ > local-model.complete prompt="Brief weather for $(CITY)" -> FORECAST
204
+ ~ memory-store.set key="weather:$(CITY|url)" value=$(FORECAST)
205
+
206
+ emit: forecast
207
+ ! Weather for $(CITY): $(FORECAST)
208
+
209
+ default: emit
210
+ ```
211
+
212
+ Eight typed operations (`!` emit, `?` ask, `??` ask-for-input, `$` set, `~` retrieve, `>` complete, `@` shell, `&` invoke-skill), three control-flow constructs (`if`/`elif`/`else`, `foreach`, `needs:`), and a small set of headers (`# Skill:`, `# Status:`, `# Vars:`, `# Requires:`, `# Triggers:`, `# Output:`, `# Timeout:`, `# OnError:`, `# Type:`).
213
+
214
+ **Full canonical reference**: [`docs/language-reference.md`](./docs/language-reference.md) — syntax, ops, semantics, lifecycle, connectors, error handling, all 1500+ lines.
215
+
216
+ ---
217
+
218
+ ## Connector model
219
+
220
+ The runtime depends on five pluggable connector contracts:
221
+
222
+ | Contract | Purpose | Bundled reference impl |
223
+ |---|---|---|
224
+ | `SkillStore` | Persist + version + filter skills | `FilesystemSkillStore` (filesystem) |
225
+ | `MemoryStore` | Cache + query memory data with TTL | `SqliteMemoryStore` (`node:sqlite`) |
226
+ | `LocalModel` | Dispatch `>` and `~` ops to a local LLM | `OllamaLocalModel` (HTTP to Ollama) |
227
+ | `McpConnector` | Dispatch `$` and `~` ops via MCP tools | `CallbackMcpConnector` (in-process) |
228
+ | `AgentConnector` | Deliver to / wake a frontier agent (T7.1) | `NoOpAgentConnector` (warns + discards) |
229
+
230
+ Wire your own impls through `Registry`:
231
+
232
+ ```typescript
233
+ import { Registry } from "skillscript-runtime";
234
+ import { MyRedisSkillStore } from "./my-adapter.js";
235
+
236
+ const registry = new Registry();
237
+ registry.registerSkillStore(new MyRedisSkillStore({ url: "redis://..." }));
238
+ registry.registerLocalModel(new OllamaLocalModel());
239
+ // ... use with execute() or Scheduler
240
+ ```
241
+
242
+ The connector resolution cascade (`# Requires:` → static capability check → runtime dispatch) is described in detail in [`docs/ERD.md`](./docs/ERD.md) §3 and the [language reference](./docs/language-reference.md).
243
+
244
+ ---
245
+
246
+ ## External adapters
247
+
248
+ The connector contracts are exported under `skillscript-runtime/connectors`:
249
+
250
+ ```typescript
251
+ import type {
252
+ SkillStore, MemoryStore, LocalModel, McpConnector, AgentConnector,
253
+ StaticCapabilities, ManifestInfo,
254
+ } from "skillscript-runtime/connectors";
255
+
256
+ export class MyCloudMemoryStore implements MemoryStore {
257
+ staticCapabilities(): StaticCapabilities {
258
+ return { connector_type: "memory-store", features: { ttl: true, query: true } };
259
+ }
260
+ // ... implement get / set / delete / query / snapshot / manifestInfo
261
+ }
262
+ ```
263
+
264
+ Adapter packages can ship publicly (npm) or privately (internal registries). The runtime treats all adapters identically as long as they conform to the typed contract. The `skillscript-runtime/testing` entry point exports `SkillStoreConformance`, `MemoryStoreConformance`, `LocalModelConformance`, `McpConnectorConformance`, and `AgentConnectorConformance` — drop-in test suites that adapter authors run against their implementation to verify contract conformance before shipping.
265
+
266
+ ### AgentConnector — delivery to frontier agents
267
+
268
+ Augmenting and Template skill outputs (`# Output: prompt-context: <agent>` and `# Output: template: <agent>`) deliver through `AgentConnector.deliver`. The contract surfaces three verbs (`list_agents`, `deliver`, `wake`) plus an optional `agent_status` probe. Substrate examples:
269
+
270
+ | Substrate | `deliver` impl | `wake` impl |
271
+ |---|---|---|
272
+ | tmux session | `tmux send-keys` to a pane | `tmux send-keys` with wake prompt |
273
+ | webhook | POST to `/augment` or `/template` endpoint | POST to `/wake` endpoint |
274
+ | file-watch | write to `<path>/augment-<id>.txt` | write to `<path>/wake-<id>.txt` |
275
+ | Slack thread | post to monitored thread | post + @mention |
276
+ | IPC named pipe | write to delivery pipe | write to wake pipe |
277
+
278
+ The bundled `NoOpAgentConnector` is the default — it logs a one-line warning and discards the payload, so the runtime starts cleanly when no agent substrate is wired. Production deployments wire a real impl through `Registry.registerAgentConnector()`.
279
+
280
+
281
+ ```typescript
282
+ import { describe } from "vitest";
283
+ import { SkillStoreConformance } from "skillscript-runtime/testing";
284
+ import { MyCloudSkillStore } from "./my-cloud-skill-store.js";
285
+
286
+ describe("MyCloudSkillStore", () => {
287
+ SkillStoreConformance(() => new MyCloudSkillStore({ /* fixture config */ }));
288
+ });
289
+ ```
290
+
291
+ ---
292
+
293
+ ## Library API
294
+
295
+ Embedders consume the runtime as a library rather than via CLI:
296
+
297
+ ```typescript
298
+ import { compile, execute, lint, Registry, Scheduler } from "skillscript-runtime";
299
+ import { FilesystemSkillStore } from "skillscript-runtime/connectors";
300
+ import { FilesystemTraceStore } from "skillscript-runtime/trace";
301
+
302
+ const skillStore = new FilesystemSkillStore("./skills");
303
+ const traceStore = new FilesystemTraceStore("./traces");
304
+ const registry = new Registry();
305
+ registry.registerSkillStore(skillStore);
306
+
307
+ const scheduler = new Scheduler({ registry, skillStore, traceStore });
308
+ const result = await scheduler.dispatchSkill("hello", { WHO: "Scott" });
309
+ console.log(result.emissions);
310
+ ```
311
+
312
+ Subpath exports for adapter authors and embedders who want narrower imports:
313
+
314
+ | Path | Content |
315
+ |---|---|
316
+ | `skillscript-runtime` | Main barrel — everything |
317
+ | `skillscript-runtime/connectors` | Connector contracts + Registry + bundled impls |
318
+ | `skillscript-runtime/errors` | `OpError` + subclasses, `LintFailureError`, `ConnectorError` |
319
+ | `skillscript-runtime/runtime` | `execute()` + helpers |
320
+ | `skillscript-runtime/trace` | `TraceStore`, `FilesystemTraceStore`, sampling |
321
+ | `skillscript-runtime/metrics` | `healthMetrics()` aggregator |
322
+ | `skillscript-runtime/scheduler` | `Scheduler` + `TriggerRegistration` |
323
+ | `skillscript-runtime/mcp-server` | `McpServer` + JSON-RPC types |
324
+ | `skillscript-runtime/testing` | Contract conformance suites |
325
+
326
+ ---
327
+
328
+ ## Contributing
329
+
330
+ The codebase prioritizes a small, agent-modifiable core. The narrow runtime + compiler + lint + connectors set lives under 5K LOC; CLI, dashboard, MCP server, and observability surfaces are tracked separately. See [`ARCHITECTURE.md`](./ARCHITECTURE.md) for a file-by-file map and [`docs/ERD.md`](./docs/ERD.md) for the engineering requirements.
331
+
332
+ Pre-flight checks:
333
+
334
+ ```sh
335
+ pnpm run typecheck
336
+ pnpm run loc-check # enforces ERD §1 LOC ceiling
337
+ pnpm test # 473+ tests
338
+ ```
339
+
340
+ Full `CONTRIBUTING.md` lands in v1.x.
341
+
342
+ ---
343
+
344
+ ## License
345
+
346
+ MIT. See [`LICENSE`](./LICENSE).
@@ -0,0 +1,33 @@
1
+ import type { SkillStore } from "./connectors/types.js";
2
+ import type { ProvenanceBlock } from "./provenance.js";
3
+ export type AuditRule = "stale-data-skill" | "missing-data-skill";
4
+ export interface AuditFinding {
5
+ rule: AuditRule;
6
+ severity: "warning" | "error";
7
+ skill_name: string;
8
+ recorded_content_hash: string;
9
+ /** Absent when the skill couldn't be found in the store. */
10
+ current_content_hash?: string;
11
+ message: string;
12
+ }
13
+ export interface AuditResult {
14
+ audited_at: string;
15
+ /** The provenance block that was audited (echoed for cross-reference). */
16
+ provenance: ProvenanceBlock;
17
+ findings: AuditFinding[];
18
+ /** True if any finding has severity error OR any stale-data-skill. */
19
+ is_stale: boolean;
20
+ }
21
+ /**
22
+ * Audit a provenance block against current SkillStore state. Returns a
23
+ * structured report; never throws on missing/stale skills — those become
24
+ * findings, not exceptions. Throws only on unexpected SkillStore errors
25
+ * (e.g., substrate down).
26
+ */
27
+ export declare function audit(provenance: ProvenanceBlock, store: SkillStore): Promise<AuditResult>;
28
+ /**
29
+ * Pretty-print an AuditResult for human display. JSON output is the canonical
30
+ * form; this is a thin formatter for CLI/dashboard surfaces.
31
+ */
32
+ export declare function formatAuditResult(result: AuditResult): string;
33
+ //# sourceMappingURL=audit.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"audit.d.ts","sourceRoot":"","sources":["../src/audit.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAC;AAExD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAEvD,MAAM,MAAM,SAAS,GAAG,kBAAkB,GAAG,oBAAoB,CAAC;AAElE,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,SAAS,CAAC;IAChB,QAAQ,EAAE,SAAS,GAAG,OAAO,CAAC;IAC9B,UAAU,EAAE,MAAM,CAAC;IACnB,qBAAqB,EAAE,MAAM,CAAC;IAC9B,4DAA4D;IAC5D,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAC9B,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,WAAW;IAC1B,UAAU,EAAE,MAAM,CAAC;IACnB,0EAA0E;IAC1E,UAAU,EAAE,eAAe,CAAC;IAC5B,QAAQ,EAAE,YAAY,EAAE,CAAC;IACzB,sEAAsE;IACtE,QAAQ,EAAE,OAAO,CAAC;CACnB;AAED;;;;;GAKG;AACH,wBAAsB,KAAK,CACzB,UAAU,EAAE,eAAe,EAC3B,KAAK,EAAE,UAAU,GAChB,OAAO,CAAC,WAAW,CAAC,CAyCtB;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,WAAW,GAAG,MAAM,CAY7D"}
package/dist/audit.js ADDED
@@ -0,0 +1,76 @@
1
+ // Recompile-staleness detection. Reads a previously-recorded provenance
2
+ // block and compares its `data_skills_inlined[].content_hash` to the
3
+ // current content_hash of each referenced skill via the SkillStore.
4
+ // Surfaces stale entries (source changed since compile) and missing ones
5
+ // (referenced skill deleted/renamed).
6
+ //
7
+ // Agent-first JSON output: every audit produces a structured `AuditResult`
8
+ // with typed findings keyed by rule ID. Human-readable display is a
9
+ // pretty-printer over the same shape.
10
+ import { SkillNotFoundError } from "./errors.js";
11
+ /**
12
+ * Audit a provenance block against current SkillStore state. Returns a
13
+ * structured report; never throws on missing/stale skills — those become
14
+ * findings, not exceptions. Throws only on unexpected SkillStore errors
15
+ * (e.g., substrate down).
16
+ */
17
+ export async function audit(provenance, store) {
18
+ const findings = [];
19
+ for (const recorded of provenance.data_skills_inlined) {
20
+ try {
21
+ const meta = await store.metadata(recorded.name);
22
+ if (meta.content_hash !== recorded.content_hash) {
23
+ findings.push({
24
+ rule: "stale-data-skill",
25
+ severity: "warning",
26
+ skill_name: recorded.name,
27
+ recorded_content_hash: recorded.content_hash,
28
+ current_content_hash: meta.content_hash,
29
+ message: `Data-skill '${recorded.name}' has been updated since this artifact ` +
30
+ `was compiled (recorded ${recorded.content_hash.slice(0, 12)}..., ` +
31
+ `current ${meta.content_hash.slice(0, 12)}...). Recompile to pick up the new content.`,
32
+ });
33
+ }
34
+ }
35
+ catch (err) {
36
+ if (err instanceof SkillNotFoundError) {
37
+ findings.push({
38
+ rule: "missing-data-skill",
39
+ severity: "error",
40
+ skill_name: recorded.name,
41
+ recorded_content_hash: recorded.content_hash,
42
+ message: `Data-skill '${recorded.name}' (recorded ${recorded.content_hash.slice(0, 12)}...) ` +
43
+ `is no longer present in the SkillStore. The compiled artifact references ` +
44
+ `content that can no longer be re-derived.`,
45
+ });
46
+ continue;
47
+ }
48
+ throw err;
49
+ }
50
+ }
51
+ return {
52
+ audited_at: new Date().toISOString(),
53
+ provenance,
54
+ findings,
55
+ is_stale: findings.length > 0,
56
+ };
57
+ }
58
+ /**
59
+ * Pretty-print an AuditResult for human display. JSON output is the canonical
60
+ * form; this is a thin formatter for CLI/dashboard surfaces.
61
+ */
62
+ export function formatAuditResult(result) {
63
+ const lines = [];
64
+ const sourceName = result.provenance.source_skill.name ?? "(unnamed)";
65
+ lines.push(`Audit of '${sourceName}' (${result.findings.length} finding${result.findings.length === 1 ? "" : "s"})`);
66
+ if (result.findings.length === 0) {
67
+ lines.push(` OK: no stale or missing references. ${result.provenance.data_skills_inlined.length} data-skill(s) audited.`);
68
+ }
69
+ else {
70
+ for (const f of result.findings) {
71
+ lines.push(` [${f.severity}] ${f.rule} (${f.skill_name}): ${f.message}`);
72
+ }
73
+ }
74
+ return lines.join("\n");
75
+ }
76
+ //# sourceMappingURL=audit.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"audit.js","sourceRoot":"","sources":["../src/audit.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,69 @@
1
+ import { Registry } from "./connectors/registry.js";
2
+ import { FilesystemSkillStore } from "./connectors/skill-store.js";
3
+ import { FilesystemTraceStore } from "./trace.js";
4
+ import { Scheduler } from "./scheduler.js";
5
+ import type { TraceConfig } from "./trace.js";
6
+ import { McpServer } from "./mcp-server.js";
7
+ export interface BootstrapOpts {
8
+ skillsDir: string;
9
+ traceDir: string;
10
+ /** When set + existing, register `SqliteMemoryStore` as primary memory_store. */
11
+ memoryDbPath?: string;
12
+ /** Override `OLLAMA_BASE_URL` env default. */
13
+ ollamaBaseUrl?: string;
14
+ /** Scheduler poll interval (default 30s). */
15
+ pollIntervalSeconds?: number;
16
+ /** Forwarded to scheduler/runtime. Default false. */
17
+ enableUnsafeShell?: boolean;
18
+ /** When set, scheduler-driven fires record traces via the result's traceStore. */
19
+ trace?: TraceConfig;
20
+ }
21
+ export interface BootstrapResult {
22
+ registry: Registry;
23
+ scheduler: Scheduler;
24
+ mcpServer: McpServer;
25
+ skillStore: FilesystemSkillStore;
26
+ traceStore: FilesystemTraceStore;
27
+ /** Read back so runtime_capabilities can surface the active mode. */
28
+ enableUnsafeShell: boolean;
29
+ }
30
+ export interface DefaultRegistryOpts {
31
+ skillsDir: string;
32
+ memoryDbPath?: string;
33
+ ollamaBaseUrl?: string;
34
+ }
35
+ /**
36
+ * Build the default connector registry: primary SkillStore + primary
37
+ * MemoryStore (if the db file/directory exists) + three named LocalModels
38
+ * pointed at Ollama. Used by both `bootstrap()` (long-lived host) and the
39
+ * `skillfile run` one-shot path so both surfaces wire the same defaults.
40
+ */
41
+ export declare function defaultRegistry(opts: DefaultRegistryOpts): {
42
+ registry: Registry;
43
+ skillStore: FilesystemSkillStore;
44
+ };
45
+ /**
46
+ * Construct the long-lived runtime surface. Caller is expected to:
47
+ * 1. Optionally call `wireDeclarativeTriggers(result)` to register
48
+ * `# Triggers:` headers from already-Approved skills.
49
+ * 2. Call `result.scheduler.start()` to arm the tick loop.
50
+ * 3. Mount any additional surfaces (e.g., `DashboardServer`) on top of
51
+ * `result.mcpServer`.
52
+ */
53
+ export declare function bootstrap(opts: BootstrapOpts): BootstrapResult;
54
+ /**
55
+ * Walk the SkillStore for Approved skills with declared `# Triggers:`
56
+ * headers and register each into the scheduler. Returns the number of
57
+ * triggers registered. Skips skills whose body fails to parse rather
58
+ * than crashing boot — operators can fix the offender and restart.
59
+ *
60
+ * Implementation note: the SkillStore's `query()` returns SkillMeta with
61
+ * an *optional* `triggers` field; not all impls populate it (the bundled
62
+ * FilesystemSkillStore does not). This helper loads + parses each skill
63
+ * source directly so it works against any SkillStore.
64
+ */
65
+ export declare function wireDeclarativeTriggers(result: Pick<BootstrapResult, "scheduler" | "skillStore">, log?: (msg: string) => void): Promise<{
66
+ registered: number;
67
+ skipped: number;
68
+ }>;
69
+ //# sourceMappingURL=bootstrap.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bootstrap.d.ts","sourceRoot":"","sources":["../src/bootstrap.ts"],"names":[],"mappings":"AASA,OAAO,EAAE,QAAQ,EAAE,MAAM,0BAA0B,CAAC;AACpD,OAAO,EAAE,oBAAoB,EAAE,MAAM,6BAA6B,CAAC;AAGnE,OAAO,EAAE,oBAAoB,EAAE,MAAM,YAAY,CAAC;AAClD,OAAO,EAAE,SAAS,EAAgC,MAAM,gBAAgB,CAAC;AACzE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAC9C,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAI5C,MAAM,WAAW,aAAa;IAC5B,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,iFAAiF;IACjF,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,8CAA8C;IAC9C,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,6CAA6C;IAC7C,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,qDAAqD;IACrD,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B,kFAAkF;IAClF,KAAK,CAAC,EAAE,WAAW,CAAC;CACrB;AAED,MAAM,WAAW,eAAe;IAC9B,QAAQ,EAAE,QAAQ,CAAC;IACnB,SAAS,EAAE,SAAS,CAAC;IACrB,SAAS,EAAE,SAAS,CAAC;IACrB,UAAU,EAAE,oBAAoB,CAAC;IACjC,UAAU,EAAE,oBAAoB,CAAC;IACjC,qEAAqE;IACrE,iBAAiB,EAAE,OAAO,CAAC;CAC5B;AAMD,MAAM,WAAW,mBAAmB;IAClC,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAED;;;;;GAKG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,mBAAmB,GAAG;IAAE,QAAQ,EAAE,QAAQ,CAAC;IAAC,UAAU,EAAE,oBAAoB,CAAA;CAAE,CAenH;AAED;;;;;;;GAOG;AACH,wBAAgB,SAAS,CAAC,IAAI,EAAE,aAAa,GAAG,eAAe,CAiB9D;AAED;;;;;;;;;;GAUG;AACH,wBAAsB,uBAAuB,CAC3C,MAAM,EAAE,IAAI,CAAC,eAAe,EAAE,WAAW,GAAG,YAAY,CAAC,EACzD,GAAG,GAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAA4D,GACjF,OAAO,CAAC;IAAE,UAAU,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC,CAkClD"}