skillscript-runtime 0.17.3 → 0.17.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.
- package/dist/bootstrap.d.ts +18 -0
- package/dist/bootstrap.d.ts.map +1 -1
- package/dist/bootstrap.js +1 -0
- package/dist/bootstrap.js.map +1 -1
- package/dist/cli.js +42 -6
- package/dist/cli.js.map +1 -1
- package/dist/dotenv-loader.d.ts +29 -0
- package/dist/dotenv-loader.d.ts.map +1 -0
- package/dist/dotenv-loader.js +86 -0
- package/dist/dotenv-loader.js.map +1 -0
- package/dist/help-content.d.ts.map +1 -1
- package/dist/help-content.js +33 -4
- package/dist/help-content.js.map +1 -1
- package/dist/lint.d.ts.map +1 -1
- package/dist/lint.js +122 -0
- package/dist/lint.js.map +1 -1
- package/dist/runtime-config.d.ts +10 -0
- package/dist/runtime-config.d.ts.map +1 -1
- package/dist/runtime-config.js +8 -0
- package/dist/runtime-config.js.map +1 -1
- package/docs/configuration.md +75 -0
- package/docs/language-reference.md +70 -13
- package/examples/skillscripts/hello-world.skill.provenance.json +1 -1
- package/package.json +1 -1
- package/scaffold/.env.example +89 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"runtime-config.js","sourceRoot":"","sources":["../src/runtime-config.ts"],"names":[],"mappings":"AAAA,wEAAwE;AACxE,6EAA6E;AAC7E,gEAAgE;AAChE,EAAE;AACF,8EAA8E;AAC9E,0EAA0E;AAC1E,0EAA0E;AAC1E,8CAA8C;AAC9C,EAAE;AACF,wEAAwE;AACxE,2EAA2E;AAC3E,0EAA0E;AAC1E,qEAAqE;AACrE,EAAE;AACF,0EAA0E;AAC1E,6EAA6E;AAC7E,4EAA4E;AAC5E,iEAAiE;AAEjE,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,EAAE,sBAAsB,EAAE,MAAM,wBAAwB,CAAC;
|
|
1
|
+
{"version":3,"file":"runtime-config.js","sourceRoot":"","sources":["../src/runtime-config.ts"],"names":[],"mappings":"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"}
|
package/docs/configuration.md
CHANGED
|
@@ -39,6 +39,81 @@ Every derived path now lives under `~/.skillscript-adopter/`; the dev instance a
|
|
|
39
39
|
|
|
40
40
|
---
|
|
41
41
|
|
|
42
|
+
## Environment variables + `.env` file
|
|
43
|
+
|
|
44
|
+
The CLI auto-loads `$SKILLSCRIPT_HOME/.env` at startup and populates `process.env` for any key not already set in the shell. Drop a `.env` next to `skillscript.config.json` and posture switches are picked up at next restart — the installer/operator pattern.
|
|
45
|
+
|
|
46
|
+
### Direct env-var reads — the runtime checks `process.env` for these
|
|
47
|
+
|
|
48
|
+
| Env var | Effect | Cascade precedence |
|
|
49
|
+
|---|---|---|
|
|
50
|
+
| `SKILLSCRIPT_HOME` | Config root (default `~/.skillscript`) | shell-set only — read before `.env` loads |
|
|
51
|
+
| `SKILLSCRIPT_FORCE_ALWAYS_DRAFT=true` | Force outside-MCP `skill_write` to Draft; closes the agent-self-approval path | env > config > default `false` |
|
|
52
|
+
| `SKILLSCRIPT_ENABLE_UNSAFE_SHELL=true` | Permit `shell(unsafe=true)` ops | env > config > default `false` |
|
|
53
|
+
| `SKILLSCRIPT_PORT=8080` | Dashboard / serve HTTP port | `--port` flag > env > config > default `7878` |
|
|
54
|
+
| `SKILLSCRIPT_HOST=0.0.0.0` | Bind address | `--host` flag > env > config > default `127.0.0.1` |
|
|
55
|
+
| `SKILLSCRIPT_MCP_CALLER_IDENTITY_HEADER=X-Agent-Id` | Inbound caller-identity header name (multi-agent MCP hosts only — see [adopter playbook](adopter-playbook.md)) | env > config > default unset |
|
|
56
|
+
| `OLLAMA_BASE_URL=http://...` | Ollama endpoint for LocalModel (default `http://localhost:11434`) | env > built-in default |
|
|
57
|
+
|
|
58
|
+
`SKILLSCRIPT_HOME` is the chicken-and-egg case — the path to `.env` requires it, so `.env` can't set it. Use shell, Docker `-e`, or systemd `Environment=` instead.
|
|
59
|
+
|
|
60
|
+
### Indirect via `${VAR}` substitution in config files
|
|
61
|
+
|
|
62
|
+
Once `.env` populates `process.env`, both `skillscript.config.json` (`runtime-config.ts`) and `connectors.json` (`connectors/config.ts`) resolve `${VAR}` references in string values at load time. So a `.env`-set var flows into:
|
|
63
|
+
|
|
64
|
+
- **`skillscript.config.json`** — any string field. Examples: `dashboard.host: "${BIND_HOST}"`, `triggersFilePath: "${TRIGGERS_PATH}"`.
|
|
65
|
+
- **`connectors.json`** — the big one for adopter wiring. Endpoints, auth tokens, child-process `env` blocks. Example:
|
|
66
|
+
|
|
67
|
+
```json
|
|
68
|
+
{
|
|
69
|
+
"amp": {
|
|
70
|
+
"class": "HttpMcpConnector",
|
|
71
|
+
"config": {
|
|
72
|
+
"endpoint": "${AMP_ENDPOINT}",
|
|
73
|
+
"headers": { "Authorization": "Bearer ${AMP_TOKEN}" },
|
|
74
|
+
"identityHeader": "X-Agent-Id"
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
`AMP_ENDPOINT` and `AMP_TOKEN` in `.env`; declarative shape committed to `connectors.json`.
|
|
81
|
+
|
|
82
|
+
### `.env` file format
|
|
83
|
+
|
|
84
|
+
Standard dotenv conventions:
|
|
85
|
+
|
|
86
|
+
```
|
|
87
|
+
# comment lines start with #
|
|
88
|
+
KEY=value
|
|
89
|
+
KEY_WITH_SPACES="value with spaces"
|
|
90
|
+
URL=https://example.com/path?key=value
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
Supported: `KEY=value`, quoted strings (double + single), `#` comment lines, blank lines, embedded equals signs in values. Rejected (logged as warnings, skipped): malformed entries without `=`, invalid key names. Missing file → no-op.
|
|
94
|
+
|
|
95
|
+
NOT supported (deliberately — use JSON config or shell-escape for these): multi-line values, variable interpolation within values (`${OTHER_VAR}` inside a value), `export KEY=value` prefix, inline comments after a value.
|
|
96
|
+
|
|
97
|
+
### Precedence summary (most-specific wins)
|
|
98
|
+
|
|
99
|
+
1. CLI flag (e.g., `--port 8080`)
|
|
100
|
+
2. Shell-set env var (`export SKILLSCRIPT_PORT=8080`)
|
|
101
|
+
3. `.env` file in `$SKILLSCRIPT_HOME`
|
|
102
|
+
4. `skillscript.config.json` field
|
|
103
|
+
5. Built-in default
|
|
104
|
+
|
|
105
|
+
### `skillfile init` seeds `.env.example`
|
|
106
|
+
|
|
107
|
+
Running `skillfile init` writes `$SKILLSCRIPT_HOME/.env.example` documenting every recognized env var. Operators copy to `.env` and edit. Re-running init never overwrites operator-edited `.env` — only writes the template.
|
|
108
|
+
|
|
109
|
+
### Adopter credential discipline
|
|
110
|
+
|
|
111
|
+
- Commit `connectors.json` with `${VAR}` references; never literal secrets.
|
|
112
|
+
- `.gitignore` `.env` (the file with real values); commit `.env.example` (the template).
|
|
113
|
+
- See [Credential discipline](#credential-discipline) below for the broader pattern.
|
|
114
|
+
|
|
115
|
+
---
|
|
116
|
+
|
|
42
117
|
## Quick start
|
|
43
118
|
|
|
44
119
|
A typical out-of-the-box `~/.skillscript/connectors.json`:
|
|
@@ -190,7 +190,7 @@ default: sweep
|
|
|
190
190
|
The joined `emit()` stream becomes the augment-kind payload delivered to the on-call agent (per `# Output: agent: oncall` declaration). The agent sees the briefing inline at next-turn dispatch.
|
|
191
191
|
|
|
192
192
|
**Three layers of declaration:**
|
|
193
|
-
1. **Header metadata** (`# Key: value` lines) — name, description, declared variables, triggers, `# Output:` routing, optional `# Autonomous:` flag, error fallbacks
|
|
193
|
+
1. **Header metadata** (`# Key: value` lines) — name, description, declared variables (`# Vars:`), declared returns (`# Returns:` — the export surface, output-side mirror of `# Vars:`; see Composition), triggers, `# Output:` routing, optional `# Autonomous:` flag, error fallbacks
|
|
194
194
|
2. **Targets** — named blocks of typed ops, optionally with `needs:` dependencies
|
|
195
195
|
3. **`default:`** — names the goal target the runtime walks toward
|
|
196
196
|
|
|
@@ -454,6 +454,8 @@ shell(command="curl -s example.com | jq '.field' > /tmp/out", unsafe=true)
|
|
|
454
454
|
|
|
455
455
|
Bash's `$(command)` and arithmetic `$((expr))` pass through to bash without escape because skillscript's substitution is braced (`${VAR}`).
|
|
456
456
|
|
|
457
|
+
**Pipes need unsafe; sandboxed multi-call + temp file is the unsafe-free alternative.** A pipe (`curl ... | jq ...`) is a shell metacharacter and requires `unsafe=true`. To compute-in-tools without unsafe, split into sequential sandboxed calls sharing a temp file: `shell(command="curl -s -o /tmp/x.json ...")` then `shell(command="jq -c '<filter>' /tmp/x.json") -> R`. Sequential sandboxed calls share the runtime's filesystem within an execution. Caveat: a fixed temp path races under concurrent invocation (no built-in uniquifier short of a `mktemp` call) — for a large fetched intermediate, keeping it in an execution-scoped var + filtering exports via `# Returns:` is usually cleaner than either shell form.
|
|
458
|
+
|
|
457
459
|
### `file_read` / `file_write` — file I/O
|
|
458
460
|
|
|
459
461
|
```
|
|
@@ -475,7 +477,7 @@ brief:
|
|
|
475
477
|
|
|
476
478
|
Inlines an Approved `# Type: data` skill into the host skill's compiled artifact at the call site. Resolved at `compile()` time; the data skill's `content_hash` is recorded in the host's provenance. `skillscript audit` detects stale recompiles when a referenced data skill changes.
|
|
477
479
|
|
|
478
|
-
**
|
|
480
|
+
**Data-only — not executable composition.** `inline` brings in *data* — the `# Type: data` skill's emitted text, resolved and baked at compile time — not executable logic. The inlined skill is not run at runtime, so there is no identity boundary: the baked text is simply part of the host's compiled artifact, attributed to the host. For *executable* composition (running another skill's logic at runtime), use `execute_skill`, where the called skill runs in its own frame under its own author identity. The two are not interchangeable — `inline` is compile-time data inclusion; `execute_skill` is runtime executable composition. There is no executable form of `inline`.
|
|
479
481
|
|
|
480
482
|
See Composition section for the distinction between `inline` (compile-time), `execute_skill` (in-skill runtime call), and dispatched skills.
|
|
481
483
|
|
|
@@ -488,6 +490,8 @@ classify:
|
|
|
488
490
|
|
|
489
491
|
Runtime-resolved against the SkillStore. Recursion-depth-guarded (default 10).
|
|
490
492
|
|
|
493
|
+
**Returns.** The caller's `-> R` binding receives `outputs` + `transcript` + execution metadata always, plus the child's declared `# Returns:` surface (each declared var accessible as `${R.X}`). Undeclared scratch is filtered — a child with no `# Returns:` yields `final_vars: {}`. This is what keeps composition from compounding (a child's internal state never propagates up). Full contract in Composition § Return contract.
|
|
494
|
+
|
|
491
495
|
**Identity semantic.** Calls run under the **called skill's author identity** (`SkillMeta.author`), not the caller's — same rule as direct dispatch. When skill A (authored by Alice) invokes skill B (authored by Bob) via `execute_skill`, B runs as Bob. Each skill is its own identity unit; the dispatcher does not loan its identity to the callee. Cross-author delegation (caller-identity threaded as a separate context) is a future-ring design surface.
|
|
492
496
|
|
|
493
497
|
---
|
|
@@ -1633,7 +1637,44 @@ execute_skill({
|
|
|
1633
1637
|
})
|
|
1634
1638
|
```
|
|
1635
1639
|
|
|
1636
|
-
**Returns:** `{ final_vars, transcript, outputs, errors, target_order, provenance }`.
|
|
1640
|
+
**Returns:** `{ final_vars, transcript, outputs, errors, target_order, provenance }`. **`final_vars` is filtered to the child's declared `# Returns:` surface** (see Return contract below) — a child with no `# Returns:` returns `final_vars: {}`. `outputs`, `transcript`, and execution metadata always propagate.
|
|
1641
|
+
|
|
1642
|
+
## Return contract: `# Returns:`
|
|
1643
|
+
|
|
1644
|
+
A skill declares its export surface with a `# Returns:` frontmatter header — the output-side mirror of `# Vars:` (input side). Skills are functions: `# Vars:` is the parameter list, `# Returns:` is the return signature.
|
|
1645
|
+
|
|
1646
|
+
```
|
|
1647
|
+
# Skill: get-weather
|
|
1648
|
+
# Status: Approved
|
|
1649
|
+
# Vars: LOCATION="Valdese"
|
|
1650
|
+
# Returns: SUMMARY, TEMP_F, CONDITIONS
|
|
1651
|
+
|
|
1652
|
+
fetch:
|
|
1653
|
+
shell(command="curl -s 'wttr.in/${LOCATION|url}?format=j1'") -> RAW
|
|
1654
|
+
$ json_parse ${RAW} -> PARSED
|
|
1655
|
+
$set TEMP_F = ${PARSED.current_condition.0.temp_F}
|
|
1656
|
+
$set CONDITIONS = ${PARSED.current_condition.0.weatherDesc.0.value}
|
|
1657
|
+
$set SUMMARY = "${LOCATION}: ${TEMP_F}°F and ${CONDITIONS}"
|
|
1658
|
+
emit(text="${SUMMARY}")
|
|
1659
|
+
default: fetch
|
|
1660
|
+
```
|
|
1661
|
+
|
|
1662
|
+
**What the caller's `-> R` binding receives:**
|
|
1663
|
+
- `R.outputs` — the delivery (emit) stream. Always exported.
|
|
1664
|
+
- `R.transcript` — execution trace. Always exported.
|
|
1665
|
+
- `R.errors`, `R.target_order`, `R.fallbacks`, `R.agent_delivery_receipts` — execution metadata. Always exported.
|
|
1666
|
+
- `R.SUMMARY`, `R.TEMP_F`, `R.CONDITIONS` — the declared returns, accessible at top level: `${R.SUMMARY}`, NOT `${R.final_vars.SUMMARY}`.
|
|
1667
|
+
- **NOT** `R.RAW`, `R.PARSED` — internal scratch. Not declared, not exported.
|
|
1668
|
+
|
|
1669
|
+
**Default — no `# Returns:` exports nothing from final_vars.** A skill without a `# Returns:` header returns `final_vars: {}`. Its `outputs`/`transcript`/metadata still propagate, so emit-driven skills (whose consumers read `${R.outputs.text}`) need no `# Returns:` at all. Declare `# Returns:` only when a caller needs structured access to specific variables.
|
|
1670
|
+
|
|
1671
|
+
**Per-level contract — composition doesn't compound.** Each skill's `# Returns:` governs only what *its* caller sees of it. In `A → B → C`, B's `# Returns:` governs what A sees of B; C's scratch never reaches A. This is what makes deep composition safe: internal state stays execution-scoped and is filtered at each boundary, so a stack of composed skills can't accumulate each other's scratch (the failure mode that motivated the contract — an undeclared large intermediate propagating up the whole chain).
|
|
1672
|
+
|
|
1673
|
+
**Top-level MCP result is filtered too.** A direct `execute_skill` MCP call of a no-`# Returns:` skill returns `final_vars: {}` — the filter applies to direct invocation, not just child-propagation. Adopters inspecting `final_vars` via the MCP tool see the declared-returns surface, not the full variable dump.
|
|
1674
|
+
|
|
1675
|
+
**Lint:**
|
|
1676
|
+
- `unknown-returns-ref` (tier-1) — `# Returns: X` where `X` isn't bound anywhere in the skill body. Same shape as undeclared-var, for the export side.
|
|
1677
|
+
- `unexported-final-var-access` (tier-2 advisory) — caller accesses `${R.X}` where `X` isn't in the called skill's `# Returns:`. Catches the "forgot to export it" footgun (forward-reference deferred-resolution if the called skill isn't yet stored).
|
|
1637
1678
|
|
|
1638
1679
|
## Semantics
|
|
1639
1680
|
|
|
@@ -1641,7 +1682,7 @@ execute_skill({
|
|
|
1641
1682
|
|
|
1642
1683
|
**Input override.** `inputs` map keys must match the child's `# Vars:` declarations. Undeclared keys are ignored. Required vars without defaults must be supplied or dispatch fails before the child starts.
|
|
1643
1684
|
|
|
1644
|
-
**Variable threading.** The parent's variable scope is sealed from the child's; the child sees only its declared `# Vars:` plus the inputs override plus ambient refs. The child's emitted result binds to the parent's named variable via `-> RESULT
|
|
1685
|
+
**Variable threading.** The parent's variable scope is sealed from the child's; the child sees only its declared `# Vars:` plus the inputs override plus ambient refs. The child's emitted result binds to the parent's named variable via `-> RESULT` (filtered to the child's `# Returns:` surface). The child's transcript surfaces through the parent's transcript with provenance attribution.
|
|
1645
1686
|
|
|
1646
1687
|
**Mechanical mode (the TestFlight property).** When `mechanical: true`, the dispatch graph renders without firing side-effect ops. `$` dispatch ops bind null; runtime-intrinsic side-effect ops bind self-describing placeholder strings. The mechanical flag propagates through recursive `execute_skill` calls — the whole sub-graph previews end-to-end, no real services touched. Authors use this to validate a multi-skill composition chain before committing to any real call.
|
|
1647
1688
|
|
|
@@ -1665,7 +1706,7 @@ Skill references (`inline(skill=...)`, `execute_skill(skill_name=...)`) are vali
|
|
|
1665
1706
|
|
|
1666
1707
|
Three distinct cases that look similar but have different intents:
|
|
1667
1708
|
|
|
1668
|
-
1. **Get a value back from another skill.** Use `execute_skill(skill_name="...") -> RESULT` and use `${RESULT}` locally. This is the composition primitive case.
|
|
1709
|
+
1. **Get a value back from another skill.** Use `execute_skill(skill_name="...") -> RESULT` and use `${RESULT}` locally — reaching declared returns (`${RESULT.X}`) or the output stream (`${RESULT.outputs.text}`). This is the composition primitive case.
|
|
1669
1710
|
|
|
1670
1711
|
2. **Delegate work to an agent as a task.** Use `# Output: template: <agent>` to route a compiled artifact through AgentConnector. The receiving agent acts on the prompt. *This is the Template-skill story* — uses compile-as-delivery, not execute-and-bind.
|
|
1671
1712
|
|
|
@@ -1694,21 +1735,36 @@ default: greet
|
|
|
1694
1735
|
|
|
1695
1736
|
call_greeting:
|
|
1696
1737
|
execute_skill(skill_name="greeting") -> GREETING_RESULT
|
|
1697
|
-
emit(text="Greeting skill said: ${GREETING_RESULT}")
|
|
1738
|
+
emit(text="Greeting skill said: ${GREETING_RESULT.outputs.text}")
|
|
1698
1739
|
|
|
1699
1740
|
default: call_greeting
|
|
1700
1741
|
```
|
|
1701
1742
|
|
|
1702
|
-
|
|
1743
|
+
(greeting is emit-only — no `# Returns:` needed; the parent reads `.outputs.text`.)
|
|
1744
|
+
|
|
1745
|
+
**Composition with input override + declared return:**
|
|
1746
|
+
|
|
1747
|
+
```
|
|
1748
|
+
# Skill: classifier
|
|
1749
|
+
# Status: Approved
|
|
1750
|
+
# Vars: TEXT=""
|
|
1751
|
+
# Returns: VERDICT
|
|
1752
|
+
|
|
1753
|
+
classify:
|
|
1754
|
+
$ llm prompt="Classify: ${TEXT}" -> VERDICT
|
|
1755
|
+
emit(text="${VERDICT}")
|
|
1756
|
+
|
|
1757
|
+
default: classify
|
|
1758
|
+
```
|
|
1703
1759
|
|
|
1704
1760
|
```
|
|
1705
1761
|
# Skill: parent-with-inputs
|
|
1706
1762
|
# Status: Approved
|
|
1707
|
-
# Vars:
|
|
1763
|
+
# Vars: INPUT="some text"
|
|
1708
1764
|
|
|
1709
1765
|
call_with_inputs:
|
|
1710
|
-
execute_skill(skill_name="
|
|
1711
|
-
emit(text="
|
|
1766
|
+
execute_skill(skill_name="classifier", inputs={"TEXT": "${INPUT}"}) -> R
|
|
1767
|
+
emit(text="Classified as: ${R.VERDICT}")
|
|
1712
1768
|
|
|
1713
1769
|
default: call_with_inputs
|
|
1714
1770
|
```
|
|
@@ -1721,7 +1777,7 @@ default: call_with_inputs
|
|
|
1721
1777
|
|
|
1722
1778
|
call_maybe_missing:
|
|
1723
1779
|
execute_skill(skill_name="might-not-exist") -> RESULT (fallback: "child unavailable")
|
|
1724
|
-
emit(text="Result: ${RESULT}")
|
|
1780
|
+
emit(text="Result: ${RESULT.outputs.text}")
|
|
1725
1781
|
|
|
1726
1782
|
default: call_maybe_missing
|
|
1727
1783
|
```
|
|
@@ -1741,11 +1797,12 @@ Renders the full dispatch chain — parent's targets in topo order, plus the chi
|
|
|
1741
1797
|
|
|
1742
1798
|
For *data skills* (skills marked `# Type: data`), the compile-time inline primitive `inline(skill="<name>")` resolves the data skill at compile time and bakes its emitted text into the parent's compiled artifact. The data skill's `content_hash` is recorded in the host's provenance; `skillfile audit` detects stale recompiles when a referenced data skill changes.
|
|
1743
1799
|
|
|
1744
|
-
`inline()` is compile-time; `execute_skill()` is runtime. Different mechanisms, different use cases.
|
|
1800
|
+
`inline()` is compile-time and brings in *data* (the data skill's emitted text); `execute_skill()` is runtime and brings in *behavior* (the child runs in its own frame, returns its declared `# Returns:` surface). Different mechanisms, different use cases. There is no executable form of `inline`.
|
|
1745
1801
|
|
|
1746
1802
|
## Authoring discipline
|
|
1747
1803
|
|
|
1748
1804
|
- Treat composition as a real cost. Each `execute_skill()` dispatch incurs the child's full execution time + side effects. Don't compose for trivial cases that could be inlined.
|
|
1805
|
+
- Declare `# Returns:` when a caller needs structured access to a child's variables. Leave it off for emit-only skills whose consumers read `.outputs.text` — the default-empty filter keeps scratch from propagating.
|
|
1749
1806
|
- Pair composition with `(fallback: ...)` when the child skill might fail and the parent has a sensible degraded path.
|
|
1750
1807
|
- Use mechanical mode to TestFlight any multi-skill chain before shipping it as a Headless skill on a cron trigger.
|
|
1751
1808
|
- Forward references work — author sibling skills in any order, validate independently. The tier-2 warning surfaces the deferred-resolution path; runtime catches genuine misses.
|
|
@@ -2120,5 +2177,5 @@ Hung dispatches hang the skill without explicit timeout configuration. Lean: ski
|
|
|
2120
2177
|
|
|
2121
2178
|
---
|
|
2122
2179
|
|
|
2123
|
-
*Rendered from `skillscript/skillscript-language-reference` — 2026-06-
|
|
2180
|
+
*Rendered from `skillscript/skillscript-language-reference` — 2026-06-04 11:28 EDT*
|
|
2124
2181
|
*Source of truth: AMP (`amp_render_document("skillscript/skillscript-language-reference")`)*
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "skillscript-runtime",
|
|
3
|
-
"version": "0.17.
|
|
3
|
+
"version": "0.17.4",
|
|
4
4
|
"description": "Runtime, compiler, lint, CLI, and dashboard for Skillscript — a small declarative language for authoring agent workflows.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Scott Shwarts <scotts@pobox.com>",
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
# Skillscript runtime — example .env file.
|
|
2
|
+
#
|
|
3
|
+
# Copy this to `.env` in the same directory ($SKILLSCRIPT_HOME) and edit
|
|
4
|
+
# the values you want set. The CLI auto-loads `.env` at startup and
|
|
5
|
+
# populates `process.env` for any key not already set in the shell.
|
|
6
|
+
#
|
|
7
|
+
# Precedence (most-specific wins):
|
|
8
|
+
# 1. CLI flag (e.g. `--port 8080`)
|
|
9
|
+
# 2. Shell env var (e.g. `export SKILLSCRIPT_PORT=8080`)
|
|
10
|
+
# 3. This `.env` (the values you set below)
|
|
11
|
+
# 4. `skillscript.config.json` field
|
|
12
|
+
# 5. Built-in default
|
|
13
|
+
#
|
|
14
|
+
# Lines starting with `#` are comments. Blank lines are ignored.
|
|
15
|
+
# Values can be quoted ("..." or '...') if they contain spaces.
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
# ─── Posture / security switches ───────────────────────────────────────
|
|
19
|
+
|
|
20
|
+
# Force every outside-MCP `skill_write` to land Draft regardless of what
|
|
21
|
+
# the body declares. Closes the agent-self-approval path — adopters
|
|
22
|
+
# wanting a human approval gate before any skill executes set this true.
|
|
23
|
+
# Default false (preserves v0.9.1 self-approval-via-body-declaration).
|
|
24
|
+
# SKILLSCRIPT_FORCE_ALWAYS_DRAFT=true
|
|
25
|
+
|
|
26
|
+
# Permit `shell(unsafe=true)` ops (full bash interpretation: pipes, $VAR,
|
|
27
|
+
# command substitution). Default false. Set true only after auditing
|
|
28
|
+
# every unsafe-shell op in your skill corpus — lint tier-2 warning fires
|
|
29
|
+
# on every appearance regardless.
|
|
30
|
+
# SKILLSCRIPT_ENABLE_UNSAFE_SHELL=true
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
# ─── Network / bind config ─────────────────────────────────────────────
|
|
34
|
+
|
|
35
|
+
# Dashboard / serve HTTP bind address. Default 127.0.0.1 (localhost-only).
|
|
36
|
+
# Container deployments set 0.0.0.0 so the host-side port-forward can
|
|
37
|
+
# reach the listener.
|
|
38
|
+
# SKILLSCRIPT_HOST=0.0.0.0
|
|
39
|
+
|
|
40
|
+
# Dashboard / serve HTTP port. Default 7878.
|
|
41
|
+
# SKILLSCRIPT_PORT=8080
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
# ─── Identity propagation (multi-agent hosts only) ─────────────────────
|
|
45
|
+
|
|
46
|
+
# Inbound HTTP header name carrying host-attested caller identity.
|
|
47
|
+
# When set, `DashboardServer` reads this header on every /rpc request
|
|
48
|
+
# and threads the value as `McpRequestCtx.callerIdentity`; the
|
|
49
|
+
# `skill_write` handler captures it as `SkillMeta.author`. Multi-agent
|
|
50
|
+
# MCP hosts (NanoClaw-style) configure this. Skip if single-user /
|
|
51
|
+
# single-tenant — author is captured from the runtime's own writer
|
|
52
|
+
# identity by default. See adopter playbook for the trust model.
|
|
53
|
+
# SKILLSCRIPT_MCP_CALLER_IDENTITY_HEADER=X-Agent-Id
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
# ─── LocalModel (Ollama) ───────────────────────────────────────────────
|
|
57
|
+
|
|
58
|
+
# Override the Ollama endpoint. Default http://localhost:11434.
|
|
59
|
+
# OLLAMA_BASE_URL=http://ollama.internal:11434
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
# ─── Substrate-specific tokens / endpoints ─────────────────────────────
|
|
63
|
+
#
|
|
64
|
+
# Any variable set here is also reachable via `${VAR}` substitution in
|
|
65
|
+
# `skillscript.config.json` and `connectors.json`. The canonical adopter
|
|
66
|
+
# pattern: secrets + endpoints in `.env` (gitignored), declarative shape
|
|
67
|
+
# in JSON configs (committed).
|
|
68
|
+
#
|
|
69
|
+
# Example wiring in connectors.json:
|
|
70
|
+
#
|
|
71
|
+
# {
|
|
72
|
+
# "amp": {
|
|
73
|
+
# "class": "HttpMcpConnector",
|
|
74
|
+
# "config": {
|
|
75
|
+
# "endpoint": "${AMP_ENDPOINT}",
|
|
76
|
+
# "headers": { "Authorization": "Bearer ${AMP_TOKEN}" }
|
|
77
|
+
# }
|
|
78
|
+
# }
|
|
79
|
+
# }
|
|
80
|
+
#
|
|
81
|
+
# AMP_ENDPOINT=https://amp.internal/rpc
|
|
82
|
+
# AMP_TOKEN=your-token-here
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
# ─── NOT settable via .env (chicken-and-egg) ───────────────────────────
|
|
86
|
+
#
|
|
87
|
+
# SKILLSCRIPT_HOME — read BEFORE this .env loads (we need HOME_DIR to
|
|
88
|
+
# find the .env). Set in your shell, Docker `-e`, or systemd Environment=
|
|
89
|
+
# directive instead.
|