Init
A thin wrapper. All the work is in scripts/init.sh; this skill exists to
ask the two questions the script cannot answer for itself, then run it.
1. Ask
Ask the human, in one short message, for:
- the memory directory — where this repository's durable memory lives.
Suggest
.agent-memoryif they have no reason to want something else. - the memory language — the language notes get written in. This is
independent of the language the agent replies in (see
agent-memory); suggestenif they have no preference.
Do not guess either value silently — a wrong memory directory is annoying to move later, and this only needs one short question.
2. Run the script
Before running it — this is the writing half, it lays files into --repo .
— confirm that directory is the repository the human meant to set up.
Several projects can be open in the same harness at once (Cursor especially),
and the shell a skill runs in is not necessarily the one the human was
talking about. One line naming it is enough.
Neither harness is trusted to hand a skill the plugin root, so do not rely on
a variable alone. Claude Code sets CLAUDE_PLUGIN_ROOT and Cursor sets
CURSOR_PLUGIN_ROOT (measured 2026-08-26), but each only in some contexts, and
a variable a harness did not set is indistinguishable here from one it did.
Locate the plugin all six ways .floppy/run locates it once installed —
the two harness variables, then AI_FLOPPY_HOME for development, then the
Claude Code cache, then Cursor's local symlink, then Cursor's cache — and fail
loudly, naming the install command, if none resolves. All six, not the first
four: on 2026-09-09 this block carried the Claude cache and stopped, so a
Cursor user whose CURSOR_PLUGIN_ROOT the harness had not set was told
"plugin not found" for a plugin .floppy/run would have resolved through
cursor_local — which on the owner's own machine is the branch that answers,
because the Cursor cache directory there exists and is empty. This block
duplicates the has_scripts chain in shim/run rather than reading it from
there, because .floppy/run does not exist yet in this repository —
creating it is the first thing the script below does — and that search
normally lives in the one file this plugin copies into a consumer, which has
to stay self-contained. tests/test-init-bootstrap.sh extracts this block and
runs it against each branch, so the two drift apart loudly rather than
silently. Run:
has_scripts() { [[ -n "${1:-}" ]] && ls "$1"/scripts/*.sh >/dev/null 2>&1; }
# A cache directory that exists but holds no scripts/*.sh is not a candidate,
# and each cache is read the way its own names allow: Claude Code's last
# segment is a version, so `sort -V`; Cursor's is a commit SHA, where any
# lexicographic sort orders by hash value rather than recency, so `ls -dt`.
claude_cache="$(ls -d "$HOME"/.claude/plugins/cache/*/floppy/*/ 2>/dev/null | sort -V | tail -n1)"
cursor_local="$HOME/.cursor/plugins/local/floppy"
cursor_cache="$(ls -dt "$HOME"/.cursor/plugins/cache/*/floppy/*/ 2>/dev/null | head -n1)"
if has_scripts "${CLAUDE_PLUGIN_ROOT:-}"; then
floppy_root="$CLAUDE_PLUGIN_ROOT"
elif has_scripts "${CURSOR_PLUGIN_ROOT:-}"; then
floppy_root="$CURSOR_PLUGIN_ROOT"
elif has_scripts "${AI_FLOPPY_HOME:-}"; then
floppy_root="$AI_FLOPPY_HOME"
elif has_scripts "$claude_cache"; then
floppy_root="$claude_cache"
elif has_scripts "$cursor_local"; then
floppy_root="$cursor_local"
else
floppy_root="$cursor_cache"
fi
if ! has_scripts "$floppy_root"; then
echo "x floppy plugin not found (a cache directory with no scripts/*.sh counts as not found)." >&2
echo " Install it: /plugin marketplace add spscream/ai-floppy && /plugin install floppy" >&2
echo " If it is installed, reinstall: `plugin update` is a no-op while the version is unchanged." >&2
exit 1
fi
bash "$floppy_root/scripts/init.sh" \
--repo . --memory-dir <their answer> --language <their answer>
This can only run this way — through the script directly, not through
.floppy/run — because .floppy/run does not exist yet in this repository;
creating it is the first thing the script does.
3. Report
Read the script's own output back in short form: what was created, and what was already there and left untouched (the script says so per file). Running this again later, on the same repository, changes nothing — that's by design, not a limitation worth apologizing for.
Point out explicitly that quota.lock was not created — see
agent-memory for why, and mention it will need a real measurement once
there is a corpus worth measuring, not before.