Teardown
nagi (凪): AI agent orchestration framework (remake nanoclaw)
npx -y skills add yukihirop/nagi --skill teardownAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
One thing to look at
- 0 stars0 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
Tear down a Nagi assistant — stop the launchd service, remove the plist, and optionally delete deploy/{ASSISTANT_NAME}/ and __data/{ASSISTANT_NAME}/. Inverse of /setup. Triggers on "teardown", "uninstall nagi", "remove assistant", "撤去", "アンインストール", "アシスタント削除".
SKILL.md
9.6 KB, as published. Nobody here has run it
Nagi Teardown
Inverse of /setup. Stops the launchd service for an assistant, removes its launchd plist, and optionally deletes its deploy/ config (including .env tokens) and __data/ runtime state (DB, logs, sessions). Shared resources — node_modules/, Docker images, source code, and other assistants' files — are left untouched.
Step 0: Language selection
Before proceeding with any other steps in this skill, ask the user which language to continue in using AskUserQuestion. Keep this initial prompt in English because the preferred language is not yet known.
- Question:
Which language should I continue in? - Options:
English,日本語 (Japanese)
Use the selected language for all subsequent user-facing messages and for every further AskUserQuestion prompt in this skill. Do not translate code, file paths, shell commands, or file contents.
UX Note: Use AskUserQuestion for all user-facing questions. Treat every removal step as destructive — confirm before running it.
1. Determine ASSISTANT_NAME
ls -d deploy/*/ 2>/dev/null | grep -v templates | sed 's|deploy/||;s|/||'
AskUserQuestion: Which assistant do you want to tear down? — show each detected name as an option. If nothing is detected, tell the user there is no deployed assistant and exit.
Use the selected name as {ASSISTANT_NAME} throughout the remaining steps.
2. Inventory what exists
Before destroying anything, gather the current state so the user can decide what to remove and so the verification at the end is meaningful:
test -d deploy/{ASSISTANT_NAME} && echo "DEPLOY_EXISTS" || echo "DEPLOY_MISSING"
test -d __data/{ASSISTANT_NAME} && echo "DATA_EXISTS" || echo "DATA_MISSING"
test -f ~/Library/LaunchAgents/com.nagi.{ASSISTANT_NAME}.plist && echo "PLIST_EXISTS" || echo "PLIST_MISSING"
launchctl list | grep -q com.nagi.{ASSISTANT_NAME} && echo "LAUNCHD_LOADED" || echo "LAUNCHD_NOT_LOADED"
# Containers that mount this assistant's __data dir (filter by absolute path so
# we don't pick up containers from another repo's same-named assistant).
ASSISTANT_DATA_PATH="$(pwd)/__data/{ASSISTANT_NAME}/"
for c in $(docker ps -q 2>/dev/null); do
docker inspect --format '{{.Id}} {{range .Mounts}}{{.Source}} {{end}}' "$c" \
| grep -F "$ASSISTANT_DATA_PATH" \
| awk '{print $1}'
done
Show the user a one-line summary of what will/can be removed (including the container count).
3. Confirm intent
AskUserQuestion (single-select): Confirm teardown of {ASSISTANT_NAME}?
- Continue — proceed to the next step
- Cancel — abort and exit
If the user picks Cancel, stop immediately and do not run any further commands.
4. Stop and unload launchd
If the orchestrator was started outside launchd (e.g. via pnpm dev in a separate shell), terminate that process first — launchctl unload only stops the launchd-managed instance, and a stray orchestrator will keep spawning containers that mount the __data/ dir we are about to delete.
If LAUNCHD_LOADED (or to be safe, just always run — the call no-ops if the service is already stopped):
launchctl unload ~/Library/LaunchAgents/com.nagi.{ASSISTANT_NAME}.plist 2>/dev/null
Verify the service is gone:
launchctl list | grep com.nagi.{ASSISTANT_NAME} || echo "STOPPED"
If it is still listed, force eviction:
launchctl bootout gui/$(id -u) ~/Library/LaunchAgents/com.nagi.{ASSISTANT_NAME}.plist 2>/dev/null
launchctl unload sends SIGTERM to the orchestrator. The orchestrator's shutdown handler closes channel adapters but detaches in-flight Docker containers rather than killing them (by design — so they survive an orchestrator restart). For teardown those containers must be stopped explicitly in Step 4.5; otherwise they keep consuming the agent's API quota and writing to mount paths that we are about to delete.
4.5. Stop in-flight Docker containers for this assistant
Container names use the pattern nagi-{channel}-{folder}-{epoch_ms} and do not include ASSISTANT_NAME. The only safe identifier is the absolute mount path. Filter containers whose mounts reference $(pwd)/__data/{ASSISTANT_NAME}/ — this avoids stopping:
- containers from other assistants in the same repo (different
__data/<other>/path) - containers from a same-named assistant in a different repo checkout (different
$(pwd))
The trailing / on $ASSISTANT_DATA_PATH is load-bearing: it relies on the orchestrator always bind-mounting child paths under __data/{ASSISTANT_NAME}/ (e.g. /groups/..., /sessions/..., /ipc/...) rather than the bare directory itself, so adjacent names like __data/{ASSISTANT_NAME}_archive/ cannot collide. If a future change ever mounts __data/{ASSISTANT_NAME} without a trailing slash, this filter will silently miss it — drop the trailing / then.
ASSISTANT_DATA_PATH="$(pwd)/__data/{ASSISTANT_NAME}/"
TARGETS=$(for c in $(docker ps -q 2>/dev/null); do
docker inspect --format '{{.Id}} {{range .Mounts}}{{.Source}} {{end}}' "$c" \
| grep -F "$ASSISTANT_DATA_PATH" \
| awk '{print $1}'
done)
if [ -n "$TARGETS" ]; then
echo "$TARGETS" | xargs docker stop
fi
docker stop sends SIGTERM (10s grace) then SIGKILL. The container's docker run --rm wrapper process on the host exits automatically once the container is removed, so no extra kill is needed.
If the user wants to preserve a long-running container (e.g. an agent in the middle of a delicate task), let them pick Cancel in Step 3 instead — there is no per-container opt-out here, because partial cleanup creates worse failure modes (zombie container writing to a deleted mount path).
5. Remove plist from LaunchAgents
rm -f ~/Library/LaunchAgents/com.nagi.{ASSISTANT_NAME}.plist
rm -f is a no-op if the file is already gone, so the PLIST_EXISTS check from Step 2 is informational only. The materialized copy under deploy/{ASSISTANT_NAME}/launchd/ is handled in Step 6 along with the rest of deploy/.
6. Choose what else to delete
Before showing the next question, remind the user: deleting deploy/{ASSISTANT_NAME}/ wipes the agent's tokens (Slack/Discord/Asana/Anthropic). If they want to preserve them for re-setup later, suggest copying deploy/{ASSISTANT_NAME}/.env somewhere outside the repo now, before they answer.
AskUserQuestion (multi-select): What else should be removed?
- deploy/{ASSISTANT_NAME}/ — config,
.envtokens, host & container entry files, group prompt defaults, materialized launchd plist. You'll have to re-paste tokens on the next setup. - __data/{ASSISTANT_NAME}/ — SQLite DB (registered groups, scheduled tasks, sessions), logs, IPC sockets. Removing this wipes group registrations and scheduled tasks for this assistant.
If the user picks neither, skip this step — only the launchd unload + plist removal stays. This is a valid choice for temporarily disabling an assistant without losing config.
For each selected target:
# deploy/{ASSISTANT_NAME}/ — config + tokens
rm -rf deploy/{ASSISTANT_NAME}
# __data/{ASSISTANT_NAME}/ — DB, logs, sessions
rm -rf __data/{ASSISTANT_NAME}
7. Verify
launchctl list | grep com.nagi.{ASSISTANT_NAME} && echo "STILL RUNNING" || echo "STOPPED"
test -f ~/Library/LaunchAgents/com.nagi.{ASSISTANT_NAME}.plist && echo "PLIST STILL THERE" || echo "PLIST GONE"
test -d deploy/{ASSISTANT_NAME} && echo "DEPLOY STILL THERE" || echo "DEPLOY GONE"
test -d __data/{ASSISTANT_NAME} && echo "DATA STILL THERE" || echo "DATA GONE"
# Same path-based filter as Step 4.5 — confirms no zombie containers remain.
ASSISTANT_DATA_PATH="$(pwd)/__data/{ASSISTANT_NAME}/"
LEFTOVER=$(for c in $(docker ps -q 2>/dev/null); do
docker inspect --format '{{.Id}} {{range .Mounts}}{{.Source}} {{end}}' "$c" \
| grep -F "$ASSISTANT_DATA_PATH" \
| awk '{print $1}'
done)
[ -z "$LEFTOVER" ] && echo "CONTAINERS GONE" || echo "CONTAINERS STILL THERE: $LEFTOVER"
Summarize what was removed and what was preserved.
What is not removed
The following are shared between assistants (or live outside this repo) and are left untouched. Remove manually if you want a fully clean machine:
node_modules/andpnpm-lock.yaml(project dependencies)- Docker images:
nagi-agent:latest,nagi-agent-opencode:latest—docker rmi nagi-agent nagi-agent-opencode - Source code under
host/,libs/,container/,deploy/templates/ ~/Library/LaunchAgents/com.nagi.*.plistfor other assistants- The Slack/Discord apps and Asana PATs themselves — the bots remain registered in those workspaces; revoke separately at api.slack.com / discord.com / app.asana.com
Linux
This skill is macOS-only (it targets launchd). On Linux, the equivalent flow is systemctl --user stop + systemctl --user disable + delete the unit file under ~/.config/systemd/user/, then run Step 6 manually.
Re-creating the assistant later
Step 5 always removes ~/Library/LaunchAgents/com.nagi.{ASSISTANT_NAME}.plist, so every recovery path goes through reinstalling that plist.
- Kept
deploy/and__data/: re-run/setup-launchd— the materialized plist still lives atdeploy/{ASSISTANT_NAME}/launchd/com.nagi.{ASSISTANT_NAME}.plistand just needs to be re-copied into~/Library/LaunchAgents/and loaded. - Kept
deploy/only: re-run/setup-launchd; the data dir will be recreated on first start. - Kept nothing: re-run
/setupfrom scratch.