Skip to content

release: v0.6.0 -- skill dependencies, repository lint - #33

Merged
lorem-dev merged 24 commits into
mainfrom
develop
Aug 22, 2026
Merged

release: v0.6.0 -- skill dependencies, repository lint#33
lorem-dev merged 24 commits into
mainfrom
develop

Conversation

@lorem-dev

Copy link
Copy Markdown
Owner

Release v0.6.0. Adds skill-to-skill dependencies end to end -- manifest field,
core graph, repository lint, CLI, and desktop UI -- plus the pre-existing
desktop architecture fix already on develop.

Skill dependencies

A skill can now declare what it needs:

skillkeeper:
  requires:
    - review/style-guide
    - formatting

skillkeeper.requires is validated strictly: a malformed entry warns and skips
the skill. A bare top-level requires: is accepted as a lenient fallback and
silently ignored when malformed, so third-party repositories using that key for
their own purposes keep working. skillkeeper.requires wins when both appear.

Installing a skill pulls in its dependencies transitively. Dependencies are
recorded in .skid.yml (schema 1 -> 2) and in the install manifest, so updating
a dependent skill updates everything it needs in the same run.

Repository lint

New command, ten stable diagnostic codes -- SK001-SK005 errors,
SK010-SK014 warnings:

skillkeeper repo lint [<id>] [--all] [--path <dir>] [--json]

Exit 0 clean, 1 warnings, 2 errors. Missing dependency targets and cycles are
lint errors, but they never block installation: the resolver warns and installs
what it can, so a broken upstream repository degrades instead of failing shut.

Desktop

Selection state is now derived rather than stored: hand-picked skills seed a
transitive closure, and everything the closure adds is shown as a dependency.
Three new badge states on the skills pages:

  • teal check -- a new skill pulled in as a dependency, with a tooltip naming it
    as such
  • yellow ! -- a dependency is gone or is about to be removed, and the skill may
    stop working; clicking it re-selects the whole closure to repair
  • already-installed dependencies keep their normal tone, since they are not new

Unchecking a dependency unchecks its dependents and their dependencies, but only
those that were not already installed before the change.

Verification

Full gate green on 2289858: cargo fmt, clippy -D warnings, 1284 Rust
tests, eslint, tsc, 999 renderer tests, coverage thresholds, renderer build,
51/51 e2e. Pre-release gate green: licenses, docs, changelog, version
consistency, conventional commits. Fixture repository (examples/test-repo)
gained cases for every resolution path, including cycles and missing targets.

Notes for the reviewer

  • app::askpass::tests::an_oversized_request_gets_no_answer_instead_of_hanging
    flakes on roughly half of full cargo test runs with ENOTCONN. It is
    pre-existing, this branch never touches that file, and the fix is one variant
    in the matches! at askpass.rs:908 -- deliberately left for its own change.
  • The desktop app was not launched visually during this work; the UI is covered
    by Storybook, unit tests, and e2e only.
  • sr-cyrl, sr-latn, and th catalog entries want a native speaker's review.

lorem-dev and others added 24 commits August 20, 2026 16:58
chore: back-merge main into develop
std::env::consts::ARCH is a compile-time constant: it names the target the
binary was built for, not the machine running it. An Intel build on Apple
Silicon runs under Rosetta and reports x86_64 -- uname -m agrees, since the
point of the translation is that the process cannot tell -- so the updater kept
fetching Intel artifacts and could never move that user to the native build. An
x64 build under the arm64 Windows emulation had the same problem.

The architecture is now probed from the system: sysctl.proc_translated on
macOS, PROCESSOR_ARCHITEW6432 on Windows. The decision is a pure function over
the compiled target and that answer, so it is tested directly; only the probe
touches the system.

skillkeeper-core's key builder now takes os and arch as arguments instead of
reading the constants itself. Deciding the real architecture requires asking
the system, which that crate deliberately cannot do, so it is told the answer
rather than guessing it.
Add `skillkeeper.requires` (strict) with a flat `requires` fallback
(lenient), plus the reference validation and skill-path rendering they
share with the group rules.
Transitive closure for install and update, reverse closure for what
breaks, and the two repository faults: a reference with no skill behind
it, and a cycle. Pure, deterministic, cycle-safe.
Persist the declarations in `.skid.yml` (schema 1 -> 2) and in the
install ledger, so a skill whose source repository is gone still knows
what it needed. `adopt_skill` carries them through reconcile.
Report a reference with no skill behind it, and a cycle, once the
repository's skill list is complete. Neither is fatal: hiding the skills
involved would cost more than the authoring mistake does.
Ten stable diagnostic codes over one repository: the dependency faults,
the conditions that were silent before (a declared hook with no HOOK.md,
an executables entry matching no file), and the resolver's own warnings
reclassified with a severity.
Expose the lint pass as `skillkeeper repo lint`, with three mutually
exclusive targets, JSON output derived from the diagnostic type rather
than hand-built, and exit codes a CI gate can rely on: a named target
that cannot be linted fails instead of reporting success.
Install and update expand to the transitive closure within the skill's
own repository; uninstall never cascades but reports the dependents it
broke, judged at each dependent's own target.
Send the declarations to the renderer and expand the install list to its
closure at apply time, so the core stays authoritative even if a preview
missed something. Grouped per repository, so a reference can never
resolve against a namesake elsewhere.
A second implementation so the tree can be drawn without a bridge round
trip per click. Ordering, reverse-closure sorting and missing-target
handling all match the core, which is the condition the duplication was
accepted on.
Store only what the user picked and derive the rest, so no state records
why a box is on and no click sequence can desynchronize it. The installed
baseline stays out of the seeds, which is what lets a broken dependency
be visible instead of silently repaired.
A teal plus for a skill installed because something else needs it, and an
orange exclamation for one whose dependency is gone, plus a checkbox tone
to match. The interactive badge stops its own click and its own
Enter/Space, so the row behind it neither toggles nor expands.
Both tooltips in every catalog, each matching its own
`skills.status.*` siblings rather than translating the English in
isolation.
Checking a skill selects its dependencies transitively and marks them as
such; an installed skill whose dependency is gone gets the orange marker
and repairs on click. The install modal derives the closure itself, since
the page hands it hand picks only.
Prop-level coverage in the shared kit, and an interactive story built on
the real reducer rather than a reimplementation of it.
Reference syntax and the strictness asymmetry, what install, update and
uninstall do, the diagnostic table and exit codes, the badge and token
meanings, and the derived selection model.
Picks up the dependency fixtures: a chain, a cycle, both declaration
forms, a duplicate, a missing target, a malformed strict block, a
cross-group reference, a declared hook with no HOOK.md, and an
executables entry matching no file.
Drives the real binary against the fixture: every diagnostic code, JSON
output, both target-misuse exits, closure install, the dependents warning
on uninstall, cycle-install termination and cross-group guidance. Also
bounds the CLI call, since a spinning binary would have stalled the whole
suite silently rather than failing.
CI treats clippy warnings as errors, which a bare `cargo clippy` run
does not surface.
Scope the installed baseline to the shown scopes, so an untracked
project's installs cannot become an unclearable pending removal; report a
grouped self reference, which the parser cannot see; judge repair per
agent; reject a lint path that is not a directory.
Mark the dependents a queued removal will break, rather than only after
it is applied, and stop tinting a retained install as a new dependency.
Every user-visible change of the feature gets a bullet under
Development. The feature's own `fix` commits are not listed: they
corrected unreleased code, so nothing a user could have seen was broken.
A candidate should not linger in the changelog as its own entry. The
0.1.1 candidates fold into 0.1.1; 0.1.2-rc.1 folds into 0.2.0, the release
that actually followed it -- 0.1.2 was never cut, so a plain delete would
have dropped four entries that shipped.
@lorem-dev
lorem-dev merged commit 2c41e74 into main Aug 22, 2026
6 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant