3 Commits
Author SHA1 Message Date
Teknium 557254faa2 fix(skills): lock guard resolves variables and relative inline code, lets reads through
- Shell variables in write targets expand from the environment plus `p=...` / `export p=...`
  assignments earlier in the command.
- Inline interpreter code that writes is refused when its working directory is inside a
  locked skill (relative paths), not only when it names the skill.
- A recursive delete/move of a directory holding the lock record is refused even when the only
  locked skill lives in skills.external_dirs.
- Reads are no longer refused: inline code counts as writing only for write-mode open(),
  write/delete/rename/copy calls and shell write forms; `find -exec` is refused only when the
  executed command itself writes.
- locked_skill_dirs resolves every lock in one walk of the skills dirs instead of one
  _find_skill search per locked name.
2026-11-01 15:47:21 -08:00
Teknium a639ed0ae4 fix(skills): close terminal lock bypasses; curator honours locks by display name
- Newlines separate commands (shlex read them as whitespace, so a second-line `sed -i` hid
  behind an `echo`).
- Wrapper options that take a value (`sudo -u root`, `xargs -n 1`) are skipped, reusing
  self_repo_guard's wrapper table.
- `( ... )` subshells restore the working directory when they close.
- `cp/mv/install/ln -t DIR` and `--target-directory=DIR` are the write destination.
- Recursive copies (`cp -r`, rsync) and archive extraction into a directory above a locked skill,
  inside a skills root, are refused: they can merge into it.
- Globs expand against the filesystem like the shell does, so `sed -i ... ops/*/SKILL.md` is
  judged by what it matches.
- The curator's auto-archive check resolves rows (frontmatter names) to the directory-keyed lock
  via tools/skill_lock.is_locked_skill.
2026-11-01 15:47:21 -08:00
Teknium 91c51e04f4 feat(skills): a locked skill can't be changed by the agent through any write path
Builds on the per-skill lock record (`hermes curator lock`): the lock now holds against the
agent everywhere, not only the background passes.

- skill_manage refuses every mutating action on a locked skill for every origin (normal turns,
  cron, subagents, review fork, curator); a corrupt sidecar still fails closed only for the
  autonomous passes so one broken file can't freeze every skill edit.
- write_file / patch hard-refuse any path inside a locked skill's directory and the lock
  record (skills/.usage.json) while any skill is locked (tools/skill_lock.path_refusal, wired
  into _check_sensitive_path).
- terminal refuses, before approvals and under --yolo, commands that write into a locked skill:
  redirections/tee, cp/mv/rm/touch/mkdir/chmod, sed/perl -i, git changes in its tree, archive
  extraction into it, inline python/bash code naming it, including after a cd into it; and the
  agent running `hermes curator unlock`. Reads and running the skill's own scripts still work.
- The curator never auto-archives a locked skill.
- Docs: "Locking a skill" rewritten for the new contract.
2026-11-01 15:47:21 -08:00