File handler
Agent skill repository that don't fit cleanly into any of my other cheese-related repositories
npx -y skills add paulnsorensen/skillz-that-grillz --skill file-handlerAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
One thing to look at
- 1 stars1 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
What its author says it does
Copied from the file, not written here
Persist, fetch, and search local artifacts produced by skills under a predictable `.skillz/<type>/<slug>` tree. Use whenever a skill needs to save scratch files, plans, notes, or other working artifacts to disk and look them up again in a later turn — for example when a user says "save this as <slug>", "where did we save the <type>", "find the <slug> we saved", or any time another skill in this repo references "the file-handler". Wraps a single dependency-free Bash script (`scripts/skillz.sh`) that exposes `save_file`, `get_file`, and `search_files` (titles + body grep). All other skills should delegate to this skill instead of inventing their own on-disk layout. Do NOT use for source code edits, version-controlled files, or anything that belongs in the project tree — this is for skill artifacts, not application files.
The file declares its own license as MIT. That is the author’s claim about this one file, and it is not the same thing as the license GitHub reports for the repository, which is listed with the other numbers below.
SKILL.md
5.5 KB, as published. Nobody here has run it
file-handler
One on-disk convention for every skill in this repo:
.skillz/
└── <type>/
└── <slug>
<type> groups artifacts by purpose (note, plan, draft, log,
…). <slug> is the filename. Both are validated — no path separators,
no .., no leading dots — so a skill can hand a user-supplied slug
straight through without sanitizing.
How to use this skill
When another skill needs to save or load a working file, shell out to
scripts/skillz.sh. Three subcommands cover the surface area:
# write content to .skillz/<type>/<slug>
scripts/skillz.sh save_file note todo "things to do"
# write stdin (preferred for multi-line content)
some_command | scripts/skillz.sh save_file plan release-cut
# read it back
scripts/skillz.sh get_file note todo
# search by title and body, optionally narrowed to a type
scripts/skillz.sh search_files todo
scripts/skillz.sh search_files release --type plan
save_file echoes the resolved path on success so callers can quote
it back to the user. get_file and search_files exit 1 when the
target / matches don't exist, so a skill can branch on ||.
Storage root
By default the tree lives at $PWD/.skillz. Override with SKILLZ_DIR
when you want a session-scoped or repo-scoped location:
SKILLZ_DIR="$HOME/.local/share/skillz" scripts/skillz.sh save_file note hello "hi"
Add .skillz/ to the repo's .gitignore if these artifacts shouldn't
be committed.
Conventions for callers
- Pick a type once and reuse it. Don't invent a new
<type>per artifact — types are buckets (note,plan,draft,log,transcript). Slugs are the unique part. - Slugs are ASCII filename-safe. Allowed:
[A-Za-z0-9._-](letters, digits, dot, underscore, hyphen — kebab-case is the preferred style, but dots for extensions and uppercase are accepted). Anything else gets rejected with exit 2. - No extension is required, but adding one (
.md,.txt,.json) helps when a user opens the file directly. - Prefer stdin over the inline content arg for anything multi-line — quoting gets fragile fast.
- Don't write through this skill for tracked source files. This is for skill scratch space, not the project tree.
Subcommand reference
save_file <type> <slug> [content]
Writes to .skillz/<type>/<slug>. If content is omitted, reads from
stdin. Parent directories are created on demand. Prints the resolved
path. Exit 2 on bad args.
get_file <type> <slug>
Prints .skillz/<type>/<slug> to stdout. Exit 1 if the file is
missing, exit 2 on bad args.
search_files <query> [--type <type>]
Two-pass search:
- Titles — case-insensitive
find -iname "*<query>*"across the storage root (or one type if--typeis supplied). - Bodies —
grep -rInfor the same query against the same scope. Binary files are skipped.
Output is sectioned (## titles then ## bodies); body hits are in
the standard <path>:<line>:<text> form so editors can jump to them.
Exit 1 when neither pass finds anything.
Why a single skill for this
Without a shared convention, each skill that needs to persist working
state ends up inventing its own (~/.cache/<skill>/, /tmp/<skill>-*,
a hidden file in $PWD, …). That fragments where users go to find
their stuff and makes cross-skill workflows harder ("the plan we drafted
last turn"). Centralizing on .skillz/<type>/<slug> plus three verbs
keeps the rest of the toolkit tiny.
When NOT to use this skill
- Application code, configs, or anything tracked in git. Edit those in place — this skill is for skill scratch space.
- Secrets.
.skillz/is plaintext on local disk. Use a secret manager (1Password, Bitwarden, age) instead. - Cross-machine sync. Files live on the local filesystem only. If you need them elsewhere, copy them out by hand or commit deliberately.
- Large binaries. The body-grep pass skips binary files, but the storage layout isn't tuned for big artifacts.
Gotchas
SKILLZ_DIRis captured at invocation, not export-once. Each shell-out re-resolves it, so changing the env between calls changes the storage root.- Slug validation rejects spaces. Pass
release-cut, notrelease cut. The regex is documented above. - Body grep uses fixed-string matching (
grep -F). Special characters (.,*,[) are matched literally. That's deliberate — users searching forv1.2.3get exactly what they typed, not a regex. - No locking. Two skills writing the same
<type>/<slug>concurrently will race; last writer wins. Use distinct slugs for parallel work.