io-cli 0.19.0 - #51
Merged
Merged
Conversation
The comment said alert #1 was dismissed as not-reachable. It was not: it closed as `fixed` at 2026-08-26T14:57:27Z, when the merge put `lru 0.18.2` in Cargo.lock, before any dismissal was issued. The plan to dismiss was overtaken by the dependency change that answered it. The unreachability evidence stays, because it is why this was never urgent and why the removal could be planned rather than rushed. What keeps the tree clean from here is the lockfile gate, not that judgement. 0.18.0's sealed record carries the same wording. It is immutable and pinned and the merge to main has happened, so that correction is stated in the release report rather than amended in.
docs: the lru alert closed as fixed, not dismissed
…d /skills Both add, edit, disable and remove entries in the configuration file, which is what Group::Configure means, and neither is an inspection — Group::Inspect's own doc says none of it changes what a turn does. The move is a correction, and the room it leaves is what /skills takes. Session 5, Turn 6, Inspect 9, Configure 6 — twenty-six commands, no group above ten.
The five bodies ride include_str! and are written into <home>/skills on start. Three guards, and each exists because Skills::discover fails a whole run rather than degrading: - a name the operator's own skills already resolve to is never written over, because two skills answering to one name is Error::Config propagated at run start and every turn of that session dies; - the 64-skill ceiling is counted before the write, because discover rejects the whole set rather than trimming it; - refresh is decided against a manifest io-cli writes, never against this release's own text, so a skill unchanged between two releases does not read as edited and stop being refreshed forever. The manifest is FNV-1a written here: no dependency is available for it, and no clock is either. It lives in the home rather than in skills/, because every .md in that directory is offered to the model.
The install runs immediately after the home is adopted and long before any contract is built: a skill written after the contract is one the first session of a new install cannot be offered. It is gated on adopt having adopted, because creating ~/.io-cli/skills for an operator who chose their own config home would silently attach a skills directory to a run they pointed elsewhere. /skills had a row in the table, a row in the palette and no arm in parse, so it resolved to the help listing — advertised and inert. Nothing asserted otherwise, because every gate here derives from COMMANDS and a row satisfies those by existing. The new gate states the property over the whole inventory instead: exactly one listed command may resolve to the help listing, and it is /help.
Origin comes from the manifest and never from the io- prefix, so a file the operator wrote called io-thing.md reads as theirs and an edited shipped skill reads as theirs too — which is what install will treat it as. The enabled set is read through the harness's own discover, so the list is what the model is offered; the disabled set is read here, because a directory holding no SKILL.md is invisible to that call, which is the whole mechanism. A rename and never a copy: a copy leaves one name resolving in both directories, which is the session-killer this release exists to avoid. No EXDEV fallback either — skills/ and skills/disabled/ cannot straddle filesystems, and the fallback would be the copy by another route.
The command table is rebuilt from GROUPS rather than edited, which also clears drift nobody could see: /steer and /compact had been listed under inspect since 0.17.0 while the code filed them under Turn, and the gate checks presence and row count but never which heading a row sits under. Also fixes a claim this release makes false. 'io-cli parses no skill file and keeps no copy of one' was true until it embedded five bodies; the true half stays.
Both refused src/skills.rs for explaining itself. The module says it writes a plain-text manifest rather than TOML, and that it decides freshness by bytes rather than by a clock — and saying either means naming the call it is deliberately not making. dependencies.rs already stripped comments for src/edit.rs, for exactly this reason, and timing.rs already built its own needles with format! so that it would not match itself. Each had solved the problem for one file and not for the files it scans. Line-oriented, so a // inside a string literal still counts as code: the stripping can only make either gate stricter.
…suite Every one of them is the shape that pass is briefed to hunt: the tests exercise each feature once, and the defect appears the second time. A session-killer first. relocate guards its destination by FILE NAME while a skill is addressed by its RESOLVED name, so a file moved back out of disabled/ could land beside a different file already answering to its name — and two skills of one name is an Err from Skills::discover that io-harness propagates at run start, killing every turn before the first completion. /skills could not report it either, because its list comes from the call that just failed. Two of the operator's own files are enough. enable now asks the question the run asks. The same asymmetry one door earlier: install skipped a disabled skill by testing disabled/<name>.md, which misses an operator file whose frontmatter claims the name. A deleted skill came back on the next start, while the release record and the README both told the operator that rm was how to be rid of one. The manifest already knew io-cli had written that name; now it is asked. The / palette's skill list is walked once at startup. Nothing changed that directory from inside a session until this release, so it now re-walks after a toggle rather than offering a skill the model's catalogue no longer has. And /skills read the home rather than the directory contract::skills_dir resolves, so with [run] skills configured it would have listed five files nothing reads and hidden the ones in force. Three controls added, each verified to fail alone under its own sabotage.
…tes are LF Windows-only red, and the defect was in the test. io-harness's split_front_matter strips `---\n` and `---\r\n` alike and trims \r off every key, so a CRLF checkout reads exactly the same; the assertion took only the first form and was therefore stricter than the thing it protects. Green on two platforms and red on the third, which is the only place it could be seen. Separately, .gitattributes pins skills/*.md to LF. Those five files are include_str!'d into the binary and written to disk verbatim, so their bytes are a product artifact: without it one release ships two different sets of them and the manifest digest of a file io wrote depends on the host it was built on. Neither change stands in for the other. Remove the attribute and the assertion still passes, because the skill still works.
io-cli 0.19.0 — ask for a thing io can do, in your own words
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Release PR for 0.19.0 — the skills io ships.
Five
SKILL.mdfiles written into~/.io-cli/skillsand offered to the model through io-harness's own skill machinery:io-permissions,io-mcp,io-provider,io-remember,io-update. Ask for a thing io can do in your own words and it happens, ending in a write you approve./skillslists every skill with what it is for, whose it is, whether it is on and the file it lives in; turning one off moves its file intoskills/disabled/./mcpand/providermove to the configure group.Gates
-D warnings.ultraship validateexit 0 over 57 checks.read_skilloff a plain-language ask and ending in a gated config write.What was found and fixed before this PR
An adversarial diff review between "gates green" and the merge found four real defects behind 1,022 passing tests, all of the second-use shape. The critical one: the destination guard on a skill file move was by file name while a skill is addressed by its resolved name, so two of the operator's own skills could end every turn of a session at run start, from
/skillsalone. All four fixed with controls.US-IO-CLI-0.19.0-I01.The Windows round found a defect in a test, not the product: the frontmatter assertion took only
---\nwhere io-harness reads---\r\ntoo.skills/*.mdis now pinned to LF so one release ships one artifact.