feat(tui): /study slash command to prime the agent on the current project
New built-in /study command that runs a single canned prompt: "Read and understand everything in the current directory." The first thing most sessions need is project context, and typing the full sentence every time is friction; /study turns that into one keystroke-saving shortcut. Dispatched through the same queue-or-start path as a typed prompt, so it behaves identically: - idle -> startTurn(studyPrompt) - busy -> queued behind the running turn, delivered next Also added to the README slash-commands table so /help output and the top-level docs stay in sync with slashCatalog.
- commit
- ce806272e0ee869ce19ff8371e96928b1a8120d9
- author
- patriceckhart · · 2026-04-21 06:59 UTC
- parent
- 51fd11f
- signature
- unsigned
- refs
- tag: v0.0.76
3 files · +18 -0
M README.md +1 -0
| @@ -187,6 +187,7 @@ Type `/` in the TUI to open the autocomplete popup. Available commands: | |||
| 187 | 187 | | `/btw` | Side chat with full context that doesn't add to the main thread. | | |
| 188 | 188 | | `/skills` | List discovered skills (SKILL.md files) and preview their bodies. | | |
| 189 | 189 | | `/compact` | Summarize the transcript into one message to free up context. | | |
| 190 | + | | `/study` | Run the canned prompt "Read and understand everything in the current directory." so the agent has full project context before you start asking targeted questions. | | |
| 190 | 191 | | `/jail` | Confine tools to the current directory. | | |
| 191 | 192 | | `/unjail` | Allow tools to touch paths outside again. | | |
| 192 | 193 | | `/reload-ext` | Hot-reload all extensions (re-read manifests, respawn subprocesses, rebuild tool registry). | | |
| @@ -187,6 +187,7 @@ Type `/` in the TUI to open the autocomplete popup. Available commands: | |||||
| 187 | | `/btw` | Side chat with full context that doesn't add to the main thread. | | 187 | | `/btw` | Side chat with full context that doesn't add to the main thread. | | ||
| 188 | | `/skills` | List discovered skills (SKILL.md files) and preview their bodies. | | 188 | | `/skills` | List discovered skills (SKILL.md files) and preview their bodies. | | ||
| 189 | | `/compact` | Summarize the transcript into one message to free up context. | | 189 | | `/compact` | Summarize the transcript into one message to free up context. | | ||
| 190 | + | | `/study` | Run the canned prompt "Read and understand everything in the current directory." so the agent has full project context before you start asking targeted questions. | | |||
| 190 | | `/jail` | Confine tools to the current directory. | | 191 | | `/jail` | Confine tools to the current directory. | | ||
| 191 | | `/unjail` | Allow tools to touch paths outside again. | | 192 | | `/unjail` | Allow tools to touch paths outside again. | | ||
| 192 | | `/reload-ext` | Hot-reload all extensions (re-read manifests, respawn subprocesses, rebuild tool registry). | | 193 | | `/reload-ext` | Hot-reload all extensions (re-read manifests, respawn subprocesses, rebuild tool registry). | | ||
M internal/agent/modes/interactive.go +16 -0
| @@ -1452,6 +1452,22 @@ func (i *Interactive) runSlash(ctx context.Context, cmd string) (done bool) { | |||
| 1452 | 1452 | i.openSkillsDialog() | |
| 1453 | 1453 | case "/compact": | |
| 1454 | 1454 | i.runCompact(ctx, false) | |
| 1455 | + | case "/study": | |
| 1456 | + | // Canned prompt that tells the agent to read every file | |
| 1457 | + | // in the current directory so its later turns have the | |
| 1458 | + | // whole project in context. Dispatched through the normal | |
| 1459 | + | // queue-or-start path so it behaves identically to | |
| 1460 | + | // typing the prompt by hand. | |
| 1461 | + | const studyPrompt = "Read and understand everything in the current directory." | |
| 1462 | + | i.mu.Lock() | |
| 1463 | + | if i.busy { | |
| 1464 | + | i.queued = append(i.queued, studyPrompt) | |
| 1465 | + | i.mu.Unlock() | |
| 1466 | + | i.invalidate() | |
| 1467 | + | break | |
| 1468 | + | } | |
| 1469 | + | i.mu.Unlock() | |
| 1470 | + | i.startTurn(ctx, studyPrompt) | |
| 1455 | 1471 | case "/jail": | |
| 1456 | 1472 | if i.cfg.Sandbox == nil { | |
| 1457 | 1473 | i.mu.Lock() | |
| @@ -1452,6 +1452,22 @@ func (i *Interactive) runSlash(ctx context.Context, cmd string) (done bool) { | |||||
| 1452 | i.openSkillsDialog() | 1452 | i.openSkillsDialog() | ||
| 1453 | case "/compact": | 1453 | case "/compact": | ||
| 1454 | i.runCompact(ctx, false) | 1454 | i.runCompact(ctx, false) | ||
| 1455 | + | case "/study": | |||
| 1456 | + | // Canned prompt that tells the agent to read every file | |||
| 1457 | + | // in the current directory so its later turns have the | |||
| 1458 | + | // whole project in context. Dispatched through the normal | |||
| 1459 | + | // queue-or-start path so it behaves identically to | |||
| 1460 | + | // typing the prompt by hand. | |||
| 1461 | + | const studyPrompt = "Read and understand everything in the current directory." | |||
| 1462 | + | i.mu.Lock() | |||
| 1463 | + | if i.busy { | |||
| 1464 | + | i.queued = append(i.queued, studyPrompt) | |||
| 1465 | + | i.mu.Unlock() | |||
| 1466 | + | i.invalidate() | |||
| 1467 | + | break | |||
| 1468 | + | } | |||
| 1469 | + | i.mu.Unlock() | |||
| 1470 | + | i.startTurn(ctx, studyPrompt) | |||
| 1455 | case "/jail": | 1471 | case "/jail": | ||
| 1456 | if i.cfg.Sandbox == nil { | 1472 | if i.cfg.Sandbox == nil { | ||
| 1457 | i.mu.Lock() | 1473 | i.mu.Lock() | ||
M internal/agent/modes/slash_suggest.go +1 -0
| @@ -40,6 +40,7 @@ var slashCatalog = []slashCommand{ | |||
| 40 | 40 | {Name: "/session", Desc: "export the current session to a .zotsession file, or import one"}, | |
| 41 | 41 | {Name: "/jump", Desc: "scroll the chat to a previous turn (or /jump <text>)"}, | |
| 42 | 42 | {Name: "/compact", Desc: "summarize and replace the transcript to free up context"}, | |
| 43 | + | {Name: "/study", Desc: "read every file in the current directory so the agent has full project context"}, | |
| 43 | 44 | {Name: "/btw", Desc: "side-chat that doesn't add to the main thread (saves tokens)"}, | |
| 44 | 45 | {Name: "/jail", Desc: "confine tools to the current directory"}, | |
| 45 | 46 | {Name: "/skills", Desc: "list discovered skills (SKILL.md files)"}, | |
| @@ -40,6 +40,7 @@ var slashCatalog = []slashCommand{ | |||||
| 40 | {Name: "/session", Desc: "export the current session to a .zotsession file, or import one"}, | 40 | {Name: "/session", Desc: "export the current session to a .zotsession file, or import one"}, | ||
| 41 | {Name: "/jump", Desc: "scroll the chat to a previous turn (or /jump <text>)"}, | 41 | {Name: "/jump", Desc: "scroll the chat to a previous turn (or /jump <text>)"}, | ||
| 42 | {Name: "/compact", Desc: "summarize and replace the transcript to free up context"}, | 42 | {Name: "/compact", Desc: "summarize and replace the transcript to free up context"}, | ||
| 43 | + | {Name: "/study", Desc: "read every file in the current directory so the agent has full project context"}, | |||
| 43 | {Name: "/btw", Desc: "side-chat that doesn't add to the main thread (saves tokens)"}, | 44 | {Name: "/btw", Desc: "side-chat that doesn't add to the main thread (saves tokens)"}, | ||
| 44 | {Name: "/jail", Desc: "confine tools to the current directory"}, | 45 | {Name: "/jail", Desc: "confine tools to the current directory"}, | ||
| 45 | {Name: "/skills", Desc: "list discovered skills (SKILL.md files)"}, | 46 | {Name: "/skills", Desc: "list discovered skills (SKILL.md files)"}, | ||