foldrun 1.2.0 → 1.3.0

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/docs/checks.md CHANGED
@@ -238,11 +238,48 @@ today.
238
238
 
239
239
  ### config/unknown-field
240
240
 
241
- *warn.* A frontmatter key in an agent, flow or tool that is one or two
242
- letters away from a field foldrun reads: `tolls:`, `triger:`,
243
- `disallowed_tools:`. YAML accepts it, so it is silently ignored, and `tolls:
244
- [web]` leaves the agent with no tools. A key that looks like no known field
245
- is left alone, since another tool may own it.
241
+ *warn or info.* A frontmatter key that this kind of file does not read. There
242
+ are three cases, each with its own message:
243
+ - **A near-miss** of a real field (`tolls:`, `triger:`, `disallowed_tools:`) is
244
+ a warning that names the field it meant. YAML accepts a typo, so it is
245
+ silently ignored, and `tolls: [web]` leaves the agent with no tools.
246
+ - **A field read somewhere else** is a warning that says where it goes.
247
+ `timeout: 3600` on an agent is a step option, so it belongs under the step
248
+ in the flow. `language:` on a flow is read from the agent or `AGENTS.md`.
249
+ - **A field like nothing foldrun reads** (`favourite_colour:`) is a note,
250
+ since another tool may own it.
251
+
252
+ ### config/wrong-type
253
+
254
+ *warn.* The right field holding the wrong kind of value: a map where a list
255
+ of names goes (`tools: {web: true}`), a list where one word goes. The runtime
256
+ does not read it. The message says what the field takes.
257
+
258
+ ### config/invalid-value
259
+
260
+ *warn.* A value that does nothing, or quietly does something else:
261
+ - `effort: extreme` runs at the model's default;
262
+ - `size: giant` becomes `large`;
263
+ - `permissionMode:` other than `plan` is ignored;
264
+ - `trigger: sometimes` never fires;
265
+ - a `schedule:` the scheduler cannot read (`every day`) never fires. This is
266
+ checked with the scheduler's own cron parser;
267
+ - an unknown HTTP method in `methods:` is dropped;
268
+ - a duration that is not one (`debounce: soon`).
269
+
270
+ Aliases count as valid: `effort: quick` is `low`. Fields another rule already
271
+ checks in depth (`network:`, `limits:`, `timezone:`, `web:`) are left to it,
272
+ so nothing is reported twice.
273
+
274
+ ### config/missing-field
275
+
276
+ *warn.* A required field is absent: a skill with no `description:` is never
277
+ loaded, because the model chooses skills by their descriptions.
278
+
279
+ Every field these four rules know is listed, with its type and values, in one
280
+ place in `@foldrun/core` (`frontmatter-fields.ts`). The editor's completions
281
+ come from the same list, so what the editor suggests and what `check`
282
+ accepts cannot drift apart.
246
283
 
247
284
  ### check/ignore-needs-reason
248
285
 
package/docs/tools.md CHANGED
@@ -1787,6 +1787,13 @@ Run `scripts/pace.py --spent <amount> --budget <amount>` from this skill's
1787
1787
  folder, then report the verdict in one sentence.
1788
1788
  ```
1789
1789
 
1790
+ | field | |
1791
+ |---|---|
1792
+ | `name` | defaults to the folder's name |
1793
+ | `description` | **required**: what it does and when to use it. A skill without one is never loaded, because the model chooses skills by their descriptions |
1794
+ | `when` | run tags: the skill is loaded only on runs carrying one of them |
1795
+ | `license`, `compatibility`, `metadata`, `allowed-tools` | the Agent Skills format's optional fields. Accepted and carried, not read by foldrun |
1796
+
1790
1797
  Only names and descriptions sit in context; the agent reads the full file when
1791
1798
  a task matches. So an agent can carry many skills for a few tokens each — which
1792
1799
  is the reason to move a procedure out of `agent.md` in the first place.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "foldrun",
3
- "version": "1.2.0",
3
+ "version": "1.3.0",
4
4
  "description": "Agents are just folders. Write them, check them, run them — on your machine.",
5
5
  "license": "SEE LICENSE IN LICENSE",
6
6
  "type": "module",
@@ -11,7 +11,7 @@
11
11
  "node": ">=22"
12
12
  },
13
13
  "dependencies": {
14
- "@foldrun/core": "^1.3.0"
14
+ "@foldrun/core": "^1.4.0"
15
15
  },
16
16
  "files": [
17
17
  "bin",
package/src/commands.mjs CHANGED
@@ -999,6 +999,10 @@ function narrowCheck(findings, root, opts, label, accountRoot = root) {
999
999
  out = out.filter((f) => want.has(f.rule) || want.has(f.rule.split("/")[0]) || want.has(categoryOf(f.rule)));
1000
1000
  }
1001
1001
  if (opts.security) out = out.filter((f) => SECURITY_CATEGORIES.has(categoryOf(f.rule)));
1002
+ // check's own skill rule already says a skill has no description, as an
1003
+ // error; the schema's note would say it twice. Only when that error is
1004
+ // still in the report — `--rule config/missing-field` keeps the note.
1005
+ out = out.filter((f) => !(f.rule === "config/missing-field" && out.some((g) => g.file === f.file && g.rule === "skill/config" && /no description|needs name and description/.test(g.message))));
1002
1006
  const file = path.join(root, ".foldrun", "check-baseline.json");
1003
1007
  if (opts.writeBaseline) {
1004
1008
  const created = new Date().toISOString();