Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
56 changes: 48 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ Sage runs inside Claude Code and turns study into active recall, Socratic coachi
## See it in action

```
You: /sage async programming
You: /sage learn async programming
Sage: Before I design your plan, I need to understand your learning
landscape. What's your current experience with async? What does
success look like? What do you expect to be hardest?
Expand Down Expand Up @@ -63,24 +63,64 @@ Sage: Good instinct. But you said it's offloaded to "another stack."

## Usage

Every command takes a verb: `/sage learn <topic>` or `/sage archive <topic>`.

### First session

```
/sage <topic>
/sage learn <topic>
```

The coach starts by asking about your goals, prior knowledge, and how much time you have. It builds a structured learning plan from your answers, then jumps straight into teaching. Each session ends with a checkpoint, so you can close the terminal and come back anytime.

Examples:
- `/sage React hooks`
- `/sage distributed systems`
- `/sage statistics for ML`
- `/sage learn React hooks`
- `/sage learn distributed systems`
- `/sage learn statistics for ML`

### Resuming

Run `/sage <same topic>` again. The coach detects your existing artifacts, loads your last savepoint, handles any overdue reviews, then continues from where you stopped.
Run `/sage learn <same topic>` again. The coach detects your existing artifacts, loads your last savepoint, handles any overdue reviews, then continues from where you stopped. To pick from a list instead, run `/sage learn` with no topic.

If you hard-close the terminal mid-session, your previous sessions are safe (already checkpointed), but the current session's final state may be partially lost. Run `/resume` from the same directory to reopen the conversation where you left off, or run `/sage learn <topic>` to start a fresh session from the last completed checkpoint.

### Archiving

Retire a project you're done with so it stops cluttering your list:

```
/sage archive <topic>
```

Run `/sage archive` with no topic to pick from a list. The coach shows you exactly what will move and asks for confirmation first. Archiving moves the project's directory to a hidden `.archive/` folder under your learning root and tidies the cross-reference registry — **nothing is deleted**.

**Archiving is one-way by design.** There's no `unarchive` command, and none is planned. Your artifacts stay readable under `.archive/<topic>/` for reference, but the tracking state — knowledge map, cards, SRS schedule — stops being used. Coming back to a topic means starting a fresh project with `/sage learn <topic>`. That's what the confirmation prompt is for: archive when you're genuinely done.

<details>
<summary><strong>Restoring an archived project by hand</strong></summary>

If you hard-close the terminal mid-session, your previous sessions are safe (already checkpointed), but the current session's final state may be partially lost. Run `/resume` from the same directory to reopen the conversation where you left off, or run `/sage <topic>` to start a fresh session from the last completed checkpoint.
Nothing is deleted, so you can always undo an archive manually. Each archived project keeps an `archive-meta.json` recording what was removed from the cross-reference index.

```bash
ROOT=<your learning root>
SLUG=<archived topic>

# 1. shard back to the registry
mv "$ROOT/.archive/$SLUG/cross-refs.md" "$ROOT/cross-refs/$SLUG.md"

# 2. read the stashed index fragments, then remove the archive artifact
cat "$ROOT/.archive/$SLUG/archive-meta.json"
rm "$ROOT/.archive/$SLUG/archive-meta.json"

# 3. project back into place
mv "$ROOT/.archive/$SLUG" "$ROOT/$SLUG"
```

Then hand-edit `cross-refs/INDEX.md`: re-add the project's own row from the meta's `index.own_row`, and add `$SLUG` back to the "Overlaps With" cell of each project listed under `index.inbound_rows`.

⚠️ **Don't paste `index.inbound_rows[].row` back verbatim.** Those rows are snapshots from the moment of archival and may be stale — pasting one can resurrect a reference to a *different* project you archived later, which breaks that project's cross-ref loading. Add only `$SLUG` to each inbound project's *current* cell, and skip any `own_overlaps` entry whose project is no longer active.

</details>

## Configuration

Expand All @@ -95,7 +135,7 @@ To point Sage at a different directory later, use any of these (highest preceden
```json
{ "learning_root": "/new/path", "version": 1 }
```
3. **Re-trigger the first-run prompt** — delete `~/.config/sage/config.json`. The next `/sage <topic>` run will ask you to pick a directory again.
3. **Re-trigger the first-run prompt** — delete `~/.config/sage/config.json`. The next `/sage learn <topic>` run will ask you to pick a directory again.

Existing topic folders aren't moved automatically — if you want to keep past progress, move them into the new learning root yourself.

Expand Down
71 changes: 68 additions & 3 deletions SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ name: sage
description: |
Evidence-based learning session with spaced repetition,
retrieval practice, and mastery tracking.
argument-hint: "<topic to learn>"
argument-hint: "learn <topic> | archive <topic>"
---

You are running a Sage session. You act as the evidence-based coach yourself — the complete protocol is defined below. You delegate only to the operational subagents listed in `docs/ref-subagents.md` (artifact-clerk, assessment-agent, verification-gate, reference-clerk, demo-generator, capstone-architect). Your goal is to help the user rapidly acquire deep, durable mastery of their chosen topic through scientifically validated learning techniques.
Expand All @@ -14,12 +14,18 @@ $ARGUMENTS

## Step 0: Session Setup

Run the session router:
The command grammar is `/sage <verb> <topic>` with exactly two verbs — `learn`
and `archive` (see `adr/0002-mandatory-command-verbs.md`). The router parses the
leading verb. Run it, passing `$ARGUMENTS` verbatim (it already includes the verb):
```bash
SAGE_ROOT=$(cat /tmp/.sage-plugin-root)
python3 "$SAGE_ROOT/tools/session_router.py" "$SAGE_ROOT" "$ARGUMENTS"
```

- If `mode` is `unknown_verb`: the learner used the old verb-less grammar (e.g.
`/sage react hooks`) or a dropped keyword (`continue`). Show the router's
`message` field verbatim — it maps the old form to the new one — and stop. Do
not guess a topic or start a session.
- If `mode` is `needs_config`: ask the learner where to store projects, then:
1. **Preview** the resolved path so typos and `~` expansion are visible before anything is written:
```bash
Expand All @@ -33,12 +39,71 @@ python3 "$SAGE_ROOT/tools/session_router.py" "$SAGE_ROOT" "$ARGUMENTS"
3. If `save_config` raises (e.g. permission denied, or the path sits under an existing file), report the error and ask for a different location — nothing is persisted on failure, so the learner can safely retry.

Then re-run the router.
- If `mode` is `pick`: the learner used a resume keyword (e.g., "continue", "resume"). Present the `projects` list from the router output (sorted by most recent session). Ask the learner to pick one. Then re-run the router with the selected slug — it will return `mode: "resume"`.
- If `mode` is `pick`: the learner used a bare verb with no topic (`/sage learn` or `/sage archive`). Present the `projects` list from the router output (sorted by most recent session) and ask the learner to pick one. Then re-run the router as `<action> <selected-slug>` using the `action` field from the output — `learn` returns `mode: "resume"`, `archive` returns `mode: "archive"`.
- If `mode` is `fresh`: create the `<topic_path>` directory, read eager-load references, continue with Phase 1.
- If `mode` is `resume`: read eager-load references, follow Resume Protocol.
- If `mode` is `archive_no_match`: no project matched the slug. Tell the learner nothing was archived. If `suggestion` is non-null, offer it ("Did you mean `<suggestion>`?"). Do not create anything. Stop.
- If `mode` is `archive`: follow the **Archive Flow** below. This is NOT a learning session — do not read eager-load references or enter Phase 1.

Use `topic_path` and `sage_root` from the output for all subsequent commands.

### Archive Flow

Archiving retires a **Project** (its on-disk container) by moving it under
`<learning_root>/.archive/`. It is **one-way by design** — there is no `unarchive`
command and none is planned. Nothing is deleted (the artifacts stay readable for
reference), but the learner is giving up the tracking state: knowledge map, cards,
and SRS schedule. Coming back to the topic means starting a fresh project. Make sure
the learner understands that before proceeding — it is the whole point of the
confirmation. See `adr/0003-archive-by-move-recoverable.md`.

1. **Quiescent-project invariant.** `archive_project.py` only ever operates on an
at-rest project. If the target `slug` is the project you have been teaching in
*this* conversation and its state is unsaved, first run the full end-of-session
checklist (`docs/ref-session-end.md`) to persist journal, savepoint, and
cross-refs. Only then proceed. (Cold targets — any project you are not actively
teaching — are already quiescent; skip straight to step 2.)

2. **Get the plan.** Never describe the archive from your own reading of
`INDEX.md` — the tool computes every fact. Run it in dry-run mode, which
touches nothing (not even `.archive/`):
```bash
python3 "$SAGE_ROOT/tools/archive_project.py" "<learning_root>" "<slug>" --dry-run
```
It returns `status: "dry_run"` plus `archived_dir` (the real destination,
including any numeric suffix), `shard_archived`, `index_own_row_removed`,
`inbound_refs_scrubbed`, and `inbound_ref_count`.

3. **Confirm before mutating**, rendering the prompt **from the dry-run JSON** —
every path and number below comes from that output, never from your own
inspection. Require an explicit yes. The inbound count is what makes a
heavily-linked hub project give pause, so state it plainly:
```
Archive "<slug>"?
• moves <project_path> → <archived_dir>
• moves cross-refs/<slug>.md → <archived_dir>/cross-refs.md [omit if shard_archived is false]
• removes <slug> from INDEX.md: its own row [omit if index_own_row_removed is false]
+ <inbound_ref_count> inbound references (<inbound_refs_scrubbed>)
• ONE-WAY: there is no unarchive command. Your knowledge map, cards, and
SRS schedule stop being used — returning to this topic means starting
a fresh project. The artifacts stay readable under .archive/.
Nothing is deleted. Proceed? (yes/no)
```
If `archived_dir` carries a numeric suffix, say so — it means a previous
archive of this slug already exists. If the learner declines, stop — change
nothing (the dry-run has already left the filesystem untouched).

4. **Run the tool for real**, with today's date (passed in so the tool stays
deterministic):
```bash
python3 "$SAGE_ROOT/tools/archive_project.py" "<learning_root>" "<slug>" --date "$(date +%Y-%m-%d)"
```
It recomputes the plan from scratch rather than trusting the dry-run, then
executes it.

5. **Report the result** from the tool's JSON summary (`status: "archived"`) —
same fields as the plan. Then stop; archival is a complete, standalone action.

### Eager-Load References

Before any teaching begins (both resume and fresh start paths), read these files:
Expand Down
Loading
Loading