πŸ“ components/memory/ Β· 03_terminal_interaction_layer.md

Chapter 3: Terminal Interaction Layer

πŸ“„ components/memory/03_terminal_interaction_layer.md

Chapter 3: Terminal Interaction Layer

In the previous chapter, Dynamic Agent Scope, we learned how the system dynamically creates folders for AI agents. Before that, Memory Hierarchy Interface showed us how files are organized.

But how do you actually use all of this?

If you have used a command line before, you are probably used to typing long commands. But for managing memory, we want an interactive dashboardβ€”something that feels like a modern app, but lives inside your text-based terminal.

This chapter introduces the Terminal Interaction Layer.

The Problem: The "Blind" Terminal

Standard terminal programs are "streams." You type a command, hit Enter, and text scrolls by. Once the text is printed, it's deadβ€”you can't click it or change it.

The Challenge:

  1. We have a list of memory files (User, Project, Agents).
  2. We have settings (Auto-memory: On/Off).
  3. We need to navigate this list and toggle settings without typing complex commands like memory --toggle-auto --select-file=./CLAUDE.md.

The Solution: A React-based TUI

We solve this using a library called Ink. Ink lets us build TUIs (Terminal User Interfaces) using React.

If you know React for the web (HTML/CSS), this is exactly the same, but:

It translates your React components into text that the terminal draws and updates instantly.

The Goal: The Dashboard

Our goal is to render a screen that looks like this:

  Auto-memory: on
  Auto-dream: off
  
> User memory
  Project memory
  Open auto-memory folder

The user can use the Up/Down Arrows to move the cursor (>) and Enter to select.

Concept 1: The Visual Layout

In MemoryFileSelector.tsx, we don't just print text strings. We build a visual tree of components.

The layout is a vertical column containing two main sections:

  1. The Header: Contains the toggles (Auto-memory, Auto-dream).
  2. The List: Contains the file options (User memory, Project memory, etc.).

Code Walkthrough: Building the Box

Here is the high-level structure of our component.

// MemoryFileSelector.tsx simplified structure
return (
  <Box flexDirection="column" width="100%">
    {/* The Header Section */}
    <Box flexDirection="column" marginBottom={1}>
      <ToggleItem label="Auto-memory" isOn={autoMemoryOn} />
      <ToggleItem label="Auto-dream" isOn={autoDreamOn} />
    </Box>

    {/* The File List Section */}
    <Select 
      options={memoryOptions} 
      onChange={handleSelect} 
    />
  </Box>
);

Explanation:

Concept 2: Keybindings (The Mouse Replacement)

Since we can't click, we rely on the keyboard. We use a custom hook called useKeybinding. This listens for specific keystrokes and runs a function when they happen.

Code Walkthrough: Listening for Keys

We need to listen for the "Enter" key (confirmation) to toggle settings or select files.

// Define what happens when the user presses "Enter"
useKeybinding('confirm:yes', () => {
  if (focusedToggle === 0) {
    // If on first line, toggle memory
    handleToggleAutoMemory();
  } else if (focusedToggle === 1) {
    // If on second line, toggle dreaming
    handleToggleAutoDream();
  }
}, { isActive: toggleFocused });

Explanation:

Concept 3: Interaction Flow

How does the system know whether you are toggling a setting or selecting a file?

The UI has two "modes" or sections:

  1. Toggle Mode: The cursor is on the top settings.
  2. Select Mode: The cursor is on the file list.

We manage this with simple state logic. When you press the Down Arrow, we check: "Are we at the bottom of the toggle list? If yes, move focus to the file list."

sequenceDiagram participant User participant AppState as React State participant UI as Terminal View User->>UI: Press Down Arrow UI->>AppState: Update focusedToggle (0 -> 1) AppState-->>UI: Re-render (Highlight 2nd line) User->>UI: Press Down Arrow (Again) UI->>AppState: Set focusedToggle = null UI->>AppState: Focus moves to <Select> list AppState-->>UI: Re-render (Highlight File List)

Internal Implementation: The Code

Let's look at MemoryFileSelector.tsx to see how we handle the "Auto-memory" toggle logic.

State Management

We use React's useState to keep track of the setting locally so the UI updates instantly.

// Initialize state with current system setting
const [autoMemoryOn, setAutoMemoryOn] = useState(isAutoMemoryEnabled);

function handleToggleAutoMemory() {
  const newValue = !autoMemoryOn;
  // 1. Save to disk (persistent settings)
  updateSettingsForSource("userSettings", {
    autoMemoryEnabled: newValue
  });
  // 2. Update UI instantly
  setAutoMemoryOn(newValue);
}

Explanation:

Rendering the Toggle Item

We use conditional rendering to change the color of the text based on focus.

// Inside the render return
<ListItem isFocused={focusedToggle === 0}>
  <Text>
    Auto-memory: {autoMemoryOn ? "on" : "off"}
  </Text>
</ListItem>

Explanation:

Bonus: Notifications

Sometimes the system updates memory in the background (like an agent finishing a task). We need to tell the user without breaking their current screen.

We use a small component called MemoryUpdateNotification.

// MemoryUpdateNotification.tsx
export function MemoryUpdateNotification({ memoryPath }) {
  // Convert full path to readable short path (e.g. "./CLAUDE.md")
  const displayPath = getRelativeMemoryPath(memoryPath);

  return (
    <Box flexDirection="column">
      <Text color="text">
        Memory updated in {displayPath} Β· /memory to edit
      </Text>
    </Box>
  );
}

This simply renders a text message. Because it is a React component, ink handles inserting it into the terminal output stream cleanly.

Summary

In this chapter, we learned:

  1. Ink: The library that brings React components to the terminal.
  2. Keybindings: Using keyboard shortcuts instead of mouse clicks for navigation.
  3. State Management: How we track cursor position and toggle settings instantly.

We have a beautiful interface to select files. But when we open a file, how does the AI know where that file is relative to everything else?

Next Chapter: Path Contextualization


Generated by Code IQ