A side pane showing the agent's previous final answers, without reasoning or tool calls

A Claude Code mod that keeps the agent's final answers in a side pane, so you can re-read the previous turn's answer without scrolling back past reasoning and tool calls.
/last opens or closes the pane.o / n while the pane has the keyboard) step through the last 20 answers of the session.At the prompt of a Claude Code terminal session:
/plugin install last-answer --marketplace eduojeda/claude-last-answer
Answer y to add the marketplace, then pick a scope.
claude plugin validate .
claude plugin test .hooks/register.tsx 75 lines1import { atom, read, update } from 'claude-code'
2import type { Register } from 'claude-code'
3
4const PANE = 'last-answer'
5const KEEP = 20
6// Newest last. `offset` counts back from the newest: 0 shows the newest.
7const answers = atom({ plugin: 'last-answer', key: 'answers' } as const, [])
8const offset = atom({ plugin: 'last-answer', key: 'offset' } as const, 0)
9
10export const register: Register = on => {
11 on('session.start', async ($, e, next) => {
12 await $.command.register({
13 name: 'last',
14 description: "Open or close the pane with the agent's previous answers",
15 })
16
17 return next(e)
18 })
19
20 on('command.run', { command: 'last' }, async $ => {
21 const isOpen = (await $.ui.panes()).some(pane => pane.id === PANE)
22 if (isOpen) {
23 await $.ui.close({ id: PANE })
24 return { text: 'Previous answer pane closed.' }
25 }
26 await $.ui.open({ id: PANE, title: 'Previous answer' })
27 return { text: 'Previous answer pane opened.' }
28 })
29
30 on('turn.complete', async ($, e, next) => {
31 if (e.agentId === undefined && e.answer.trim() !== '') {
32 await update($, answers, list => [...list, e.answer].slice(-KEEP))
33 await update($, offset, () => 0)
34 }
35
36 return next(e)
37 })
38
39 on('ui.render', { component: 'Pane', requestId: PANE }, async ($, e) => {
40 const { Box, Text, Button, Markdown } = $.ui.resolve(e)
41 const list = await read($, answers)
42 if (list.length === 0) {
43 return <Text dimColor>No answers yet this session.</Text>
44 }
45
46 const back = Math.min(await read($, offset), list.length - 1)
47 const position = list.length - back
48
49 return (
50 <Box flexDirection="column">
51 <Box>
52 <Text dimColor>{`${position} of ${list.length} `}</Text>
53 {back < list.length - 1 && (
54 <Button
55 key="older"
56 label="◀ older"
57 hotkey="o"
58 onPress={() => update($, offset, n => n + 1)}
59 />
60 )}
61 {back > 0 && (
62 <Button
63 key="newer"
64 label="newer ▶"
65 hotkey="n"
66 onPress={() => update($, offset, n => n - 1)}
67 />
68 )}
69 </Box>
70 <Markdown key="answer" text={list[list.length - 1 - back] ?? ''} />
71 </Box>
72 )
73 })
74}
75types/index.d.ts 8 lines1export type Answer = string
2
3declare module 'claude-code' {
4 interface PluginState {
5 'last-answer': { answers: Answer[]; offset: number }
6 }
7}
8