| name | ai-archive |
| description | Retire one finished work folder by moving it into the working root's .archive/ directory and transferring its manifest row. Invoke ONLY via the /ai-archive slash command. Do not activate from intent, keywords, or near-synonyms — slash incantation is required. |
| effort | medium |
Agent: Archive a Work Folder
You retire one finished folder from the working root. The folder moves to
<output_root>/.archive/<name>/, its row leaves the working manifest, and a row for it
appears in a second manifest inside the archive directory.
The working manifest gains a row per folder and never loses one, so the table meant to
answer "what am I working on" degrades into a project history. This skill is the only thing
that removes a row.
This is the only skill in the set that performs a destructive, hard-to-reverse filesystem
mutation. Every other skill writes a new artifact or edits one in place. There is no test
framework for skills, so nothing catches a wrong move after the fact. The safety is in the
three gates below — the status confirmation, the collision stop, and the tracking check —
and skipping any of them can lose a user's work.
User Input
$ARGUMENTS
Expected format: <name-or-path> — one folder per invocation.
Step 1: Read the Context
Read .context/README.md from the project root.
- If the file does not exist:
- Tell the user: "No project context found at
.context/README.md. Run /ai-init first."
- Stop. Without a context file there is no
output_root, so there is nothing safe to move.
- If the file exists: parse the YAML frontmatter and extract
output_path (default:
docs/working) as <output_root>.
- If
output_path is not a string, print:
WARN: "output_path in .context/README.md is not a string. Defaulting to
docs/working, please run /ai-init to set a custom output path."
Do NOT block — this is a warning, not a hard gate. The STOP above applies only to a
missing context file.
Step 2: Resolve the Argument
If $ARGUMENTS is empty, list the folders under <output_root>/ with their manifest states
and ask which to archive. Archive nothing until answered.
$ARGUMENTS is either a bare name or a path.
A path — anything containing a /. Resolve it and confirm it sits under
<output_root>. Reject anything outside with: "<path> is not under the working root
<output_root>. /ai-archive only archives work folders." Then stop. A path that resolves
to <output_root> itself, or to a file rather than a directory, is rejected the same way.
Strip any trailing slash before comparing, and reject a path whose resolved form escapes
the working root via ...
A bare name — apply steps (a) and (b) of the shared resolution order in
ai-skills-reference/manifest-update.md. Read that reference rather than reconstructing the
order from memory:
a. EXACT — if `<output_root>/<typed-name>/` exists, use it. Stop here.
b. DATED-SUFFIX — list `<output_root>/` and collect entries matching
`????-??-??-<typed-name>` exactly (an 11-character `YYYY-MM-DD-` prefix followed by the
typed name and nothing else).
- Exactly one match: use it. Tell the user which dated folder resolved.
- More than one match: list every candidate with its date and ask which to use.
Never silently pick one, and never pick the newest by default.
Do NOT implement step (c) AUTO-CREATE. On no match, print "No folder in <output_root>/
matched <typed-name> by exact or dated-suffix match. Nothing was archived." and stop.
Creating a folder in order to archive it is nonsense, and the shared reference already
anticipates skills in this position: skills that do not create folders stop at step (b).
Call the folder that resolved <name> — it may carry a date prefix the user did not type.
Every path below uses it.
Step 3: Check the Status
Read <output_root>/<name>/README.md and find its ## Status section.
If - [x] Complete is present, proceed.
If it is absent, use AskUserQuestion. State which item is checked (or that none is), then
ask:
- "Archive anyway" — proceed to Step 4
- "Cancel" — stop, moving nothing
Archiving abandoned work is legitimate, so this is a confirmation and not a refusal. A
refusal would push the user to check [x] Complete falsely just to get past the gate, which
corrupts the one status item a human owns.
If the README is missing entirely, say so and ask the same question — a folder with no
identity document is more likely to be an accident than a finished piece of work.
Step 4: Check for a Destination Collision
If <output_root>/.archive/<name>/ already exists, STOP. Print:
`<output_root>/.archive/<name>/` already exists. Nothing was moved.
Rename one of the two folders and run /ai-archive again.
Never merge. A recursive move into an existing directory interleaves two folders' artifacts,
producing a folder whose research.md and plan.md came from different work — a corruption
that reads as success and is not recoverable by re-running anything.
Step 5: Create the Archive Directory
mkdir -p <output_root>/.archive/
Run this before the move. git mv fails with fatal: renaming ... failed: No such file or directory when the destination's parent is absent, so a first archive on a fresh project
fails without it. Verified.
Step 6: Select the Move Command from Tracking State
This branch decides whether archiving preserves the work or destroys it. It is a rule,
not a judgement call — do not substitute your own reading of "move the directory".
git rev-parse --is-inside-work-tree 2>/dev/null
git ls-files --error-unmatch "<output_root>/<name>" >/dev/null 2>&1
Then branch on the result:
git mv "<output_root>/<name>" "<output_root>/.archive/<name>"
mv "<output_root>/<name>" "<output_root>/.archive/<name>"
Plain mv on a tracked folder makes git record a deletion. After the next commit,
the archived content is absent from every future checkout — it survives only in history,
recoverable with git show <commit>:<path>, which is not what a user asking to "archive"
expects. Verified in a scratch repository: git mv produces
R .../2026-08-05-foo/research.md -> .../.archive/2026-08-05-foo/research.md and the file
is present in a fresh clone; plain mv plus git add -A produces
D .../2026-08-05-foo/research.md and the file is gone from the clone.
git mv needs no -f even when the destination is gitignored, which .archive/ usually is.
Do not add it — -f would let the command overwrite an existing destination, and Step 4
exists precisely to stop that.
If git mv fails for any other reason, report the error and stop. Do not fall back to plain
mv — the fallback is the destructive path.
Step 7: Remove the Working-Manifest Row
Find the folder's row in <output_root>/README.md and delete it with the Edit tool,
preserving every other row unchanged. The row looks like:
| [<name>](<name>/) | <emoji> <State> | <first sentence of Description> |
Capture the row's full text before deleting — Step 8 transplants it.
If no row exists, note it and continue. Report it in Step 10 as an unexpected condition
rather than treating absence as success. Nothing reconciles the manifest against disk, so a
folder that no skill ever registered is a real case — this repository has had two at once.
A silent partial success here would hide the inconsistency instead of surfacing it.
Update the "Last updated" date in the blockquote to today's date from date +%F.
Step 8: Write the Archive Manifest
Create or update <output_root>/.archive/README.md:
# Archived Work
> Folders retired from the working manifest. Last updated: <YYYY-MM-DD>
| Folder | State | Archived | Description |
|--------|-------|----------|-------------|
| [2026-08-05-foo](2026-08-05-foo/) | ✅ Complete | 2026-08-05 | First sentence of Description. |
The working manifest's three columns plus Archived. Transplant the captured row
verbatim and insert the archived date, obtained from date +%F — run it, do not recall it.
The row's link needs no rewriting. [foo](foo/) is relative to the manifest's own location,
so once the row lives in .archive/README.md it resolves to <output_root>/.archive/foo/
— correct as written.
The Archived column carries the only retirement date that exists anywhere. A folder name's
date prefix records creation and is never rewritten, so without this column nothing
records when a folder stopped being active and the archive table sorts by an increasingly
irrelevant key.
If the row was missing from the working manifest, build one from the folder's README —
title, state from its ## Status per the state-emoji key in
ai-skills-reference/manifest-update.md, and the first sentence of its ## Description.
Maintain alphabetical order in the table (for YYYY-MM-DD- names this is also chronological
order, oldest first; undated legacy rows sort after dated ones because digits precede letters
in ASCII). Update the "Last updated" date. Preserve all other rows unchanged.
The state does not change. The ladder is 🆕 → 🔬 → 🛠️ → ✅ and there is no archived
state. Archiving changes a folder's location, so the row moves between two manifests
carrying whatever state it already had. Never check Complete on the folder's behalf —
only a human does that.
Step 9: Do Not Update the Folder's Status
This skill writes nothing inside the archived folder. It does not check a status item, add
an archived marker, or edit the README. The folder is retired as-is, so that restoring it is
a move in one direction with nothing to undo.
Step 10: Report
Tell the user:
Archived: <output_root>/<name>/ → <output_root>/.archive/<name>/
Move command: <git mv | mv> (<source was tracked by git | source was untracked | no git repository>)
Working manifest: row removed
Archive manifest: row added with Archived date <YYYY-MM-DD>
To restore:
<git mv | mv> <output_root>/.archive/<name> <output_root>/<name>
Then report anything unexpected, each on its own line:
- the working manifest had no row for this folder
- the folder's Status did not show
[x] Complete and you confirmed
- the folder had no README.md
If none applies, say the run was clean. Do not omit this section — the missing-row case is
the one a user would otherwise never learn about.
Print the restore command with the same command the move used: a tracked working root wants
git mv back, an untracked one wants plain mv. There is no /ai-unarchive; this line is
the whole restore path.
What This Skill Does NOT Do
- No un-archiving. Restoring is the move in the other direction, and Step 10 prints the
exact command. Wrapping a one-line
mv in a second skill buys nothing.
- No archiving of individual artifacts. This moves whole folders. A separate nested
.archive/ pattern exists inside some work folders, retiring superseded artifacts within
a live folder — a different thing, and not what this skill does.
- No bulk form. One folder per invocation. No multiple names, no "archive everything
complete" sweep.
- No compression or pruning of archived content. The bytes move unchanged.
- No manifest reconciliation. The skill reports a missing row (Step 7) but does not
sweep the whole table against disk.
- No fifth status state. See Step 8.