memo-agent

agent
Guvenlik Denetimi
Basarisiz
Health Uyari
  • License — License: MIT
  • Description — Repository has a description
  • Active repo — Last push 0 days ago
  • Low visibility — Only 5 GitHub stars
Code Basarisiz
  • exec() — Shell command execution in __tests__/db.test.ts
  • rm -rf — Recursive force deletion command in __tests__/guard.test.ts
  • os.homedir — User home directory access in __tests__/guard.test.ts
  • process.env — Environment variable access in __tests__/pathUtils.test.ts
  • os.homedir — User home directory access in src/config/loader.ts
  • process.env — Environment variable access in src/config/loader.ts
Permissions Gecti
  • Permissions — No dangerous permissions requested
Purpose
This is a terminal-based AI assistant built with TypeScript that connects to OpenAI-compatible APIs. It provides persistent memory, MCP tool extensions, and intelligent context compression directly in your command line.

Security Assessment
Risk: Medium. The tool explicitly executes shell commands and accesses the user's home directory to load configurations. It also reads environment variables to retrieve API keys. While it includes a built-in permission guard and sandboxing features designed to restrict dangerous operations and protect secrets from child processes, the underlying execution capabilities require caution. No hardcoded secrets were detected, but it does make network requests to external APIs and web search engines. The most concerning code flags (like `rm -rf` and shell execution) were found within test files rather than core runtime code.

Quality Assessment
The project uses the standard MIT license and has a clear description. It appears actively maintained with very recent repository updates. However, it currently has low community visibility with only 5 GitHub stars, which means it hasn't been broadly peer-reviewed or battle-tested. The documentation is thorough, detailing features like session archiving, slash commands, and tool caching, which reflects a mature approach to feature design.

Verdict
Use with caution. It offers well-designed safety features, but low community adoption and inherent shell execution capabilities mean you should review the sandbox configuration closely before deployment.
SUMMARY

memo-agent is a terminal-based AI assistant application (Hermes Agent simplified version), built with TypeScript + React + Ink. It connects directly to OpenAI-compatible APIs and features persistent memory, MCP tool extensions, and intelligent context compression.

README.md

memo-agent

CI
npm version
Node.js
License: MIT

中文文档

memo-agent is a terminal-based AI assistant application (Hermes Agent simplified version), built with TypeScript + React + Ink. It connects directly to OpenAI-compatible APIs and features persistent memory, MCP tool extensions, and intelligent context compression.


Features

  • Persistent MemoryNOTES.md retains context across sessions and is automatically injected into the system prompt every round; when auto_update is enabled, it automatically evaluates and writes at the end of each round
  • Session Chain Archiving — When context compression is triggered, a new session is created and linked to the old session via parent_session_id, ensuring history is never lost
  • Three-Zone Context Compression — Automatically archives the middle history for extra-long conversations, preserving the first round and the most recent ~20k tokens, so conversations are never truncated
  • Slash Commands/notes, /history, /search, /compact, /cost, /plan, and more; use /help to see all available commands
  • Plan-Execute-Reflect Loop/plan <goal> triggers a three-phase agentic loop: planning (task breakdown), execution (per-task tool loop in dependency order), and reflection (read-only review); progress is streamed live to the UI
  • Task Persistence — Tasks created by the agent are stored in SQLite, scoped to the session, and survive /resume
  • Recipes System — Custom .md template files; invoke with /recipe-name [args] in one click; supports watchPaths to auto-recommend related recipes when matching files are modified
  • MCP Tool Extensions — Connect to external tool servers via the Model Context Protocol
  • Web Search — Built-in WebSearch tool powered by Brave Search; configure search.apiKey to let the agent search the web autonomously
  • Tool Result Cache — Read-only tool results are cached for 30 seconds; cleared automatically when files are modified
  • Session Persistence — SQLite stores all history; /resume restores any historical session; supports full-text search
  • Profile Isolation — Multiple profiles with independent configurations, memory, and session data, completely isolated from each other
  • Permission Guardask/auto modes; dangerous commands (e.g., rm -rf) force confirmation; path safety restrictions; supports disabledTools to completely block specified tools
  • RunCommand Sandbox — When permissions.sandbox.enabled: true, child processes only inherit an explicit env-var allowlist, keeping API keys and secrets out of subprocess scope
  • Rich Text UI — Rendered with React + Ink, streaming output, status bar displays token usage and cost in real time
  • Enhanced Input — Cursor positioning (←/→ to move, edit mid-line), history navigation (↑/↓), queued input during streaming without loss

Installation

Via npm (recommended)

npm install -g memo-agent

Then configure your API key (choose one method):

Option A — Environment variable:

export MODEL_API_KEY=sk-...
export MODEL_BASE_URL=https://api.openai.com/v1   # optional, defaults to OpenAI
export MODEL_NAME=gpt-4o                           # optional, defaults to gpt-4o
memo

Option B — Config file:

mkdir -p ~/.memo-agent
cat > ~/.memo-agent/config.yaml << 'EOF'
model:
  base_url: "https://api.openai.com/v1"
  api_key: "sk-..."
  name: gpt-4o
EOF
memo

Via npx (no install)

MODEL_API_KEY=sk-... npx memo-agent

Quick Start (from source)

Install Dependencies

npm install

Configuration

Copy the example configuration file and fill in your API details:

cp .env.example .env
MODEL_BASE_URL=https://api.openai.com/v1
MODEL_API_KEY=sk-...
MODEL_NAME=gpt-4o

Or create ~/.memo-agent/config.yaml (see Configuration File).

Launch

# Development mode (tsx hot reload)
npm run dev

# Build and run
npm run build
npm start

# Global installation from source
npm install -g .
memo

CLI Arguments

memo [options]

OPTIONS
  --profile <name>        Use the specified profile (default: "default")
  --model <name>          Override the model name in config
  --resume <session-id>   Resume a specific historical session
  --auto                  Start in auto permission mode (no confirmation)
  --version, -v           Print version number
  --help, -h              Print help

Examples:

memo --profile work
memo --model gpt-4o-mini
memo --resume abc12345
memo --auto

Terminal Input Operations

Operation Effect
/ Move cursor within the input line; supports mid-line insertion or deletion
/ Switch through input history (up to 50 entries); ↓ returns to current editing content
Backspace / Delete Delete character to the left of the cursor
Paste / Multi-character input Cursor correctly jumps to the end of all characters
Typing during streaming Characters are queued (gray + (queued)); can continue editing after idle
Ctrl+C (during streaming) Interrupt the request; already streamed content remains on screen (marked [interrupted])
Ctrl+C (idle, press twice) Exit

Status Bar

The bottom status bar displays in real time:

● memo-agent │ gpt-4o    tokens: 1234/128k (15%)  │  $0.0042  │  mode:ask  │  profile:default
Field Description
/ Streaming / idle
tokens Session used tokens / model limit; turns yellow above 70%, red above 85%
$X.XXXX Estimated session cost (USD)
mode Current permission mode (ask / auto)
profile Current profile name

Slash Commands

Enter the following commands during a conversation:

Command Description
/help Display all available commands and recipes
/plan <goal> Run Plan-Execute-Reflect agentic loop for a goal
/notes [show|clear] View or clear persistent notes (NOTES.md)
/history [n] Show the last n sessions (default 10)
/search <keyword> Full-text search all historical messages
/compact [focus description] Manually trigger context archival compression
/model [name] View or switch the current model
/cost Show current session token consumption and estimated cost
/clear Clear the current session context (memory is preserved)
/resume [session-id] Prompt to resume a session using the --resume argument
/profile [name] View or switch profile
/recipes List installed recipes
/mode [ask|auto] Switch tool execution permission mode
/exit Exit memo-agent (alias: /quit)

Agentic Plan Loop (/plan)

/plan <goal> triggers a three-phase autonomous loop:

  1. Plan — The agent calls CreateTask to break the goal into 3–7 tasks with explicit dependencies. No other actions occur in this phase.
  2. Execute — Tasks are executed in topological order (blocked tasks wait for their prerequisites). Each task runs a full tool-call loop with the complete tool set.
  3. Reflect — After all tasks finish, the agent reviews results with read-only tools and writes a summary.

Progress events are streamed to the UI in real time:

● Planning tasks...
● Task 1/3: Set up project structure
✓ Set up project structure
● Task 2/3: Implement core logic
✓ Implement core logic
● Reflecting on results...

Recipes System

A recipe is a reusable prompt template stored as a .md file.

Storage Locations

  • Global: ~/.memo-agent/recipes/
  • Project-level (priority): .memo-agent/recipes/

Recipe File Format

---
name: review
description: Perform a code review on current changes
allowedTools: [ReadFile, SearchCode, ListFiles]
---
Please perform a code review on the following changes, focusing on security, performance, and maintainability.

$ARGUMENTS
Field Description
name Invocation name (lowercase letters + hyphens)
description Description shown in the /recipes list
allowedTools Tools pre-authorized during recipe execution (skips permission confirmation)
watchPaths Auto-recommend this recipe when file paths match (optional)
$ARGUMENTS Placeholder for arguments passed during invocation

Invoking a Recipe

/review src/main.ts
/fix-types
/summarize-pr

Persistent Memory

NOTES.md — Working Notes (Read/Write)

Path: ~/.memo-agent/memory/NOTES.md (or under the profile directory)

  • The agent can append notes via the WriteNotes tool
  • When memory.auto_update: true is enabled, it automatically evaluates whether information is worth retaining and writes it at the end of each round; saved content is displayed in the terminal upon writing
  • Automatically injected into the system prompt at the start of each session
  • /notes show to view, /notes clear to clear

PROFILE.md — User Preferences (Read-Only)

Path: ~/.memo-agent/memory/PROFILE.md

Only editable by the user; the agent will not modify it. Suitable for placing:

I am a backend engineer, primarily using Go and TypeScript.
Code style: functional-first, avoid over-abstraction.
Please respond in Chinese; code comments in English.

Context Compression

Conversation context is managed in three zones:

┌──────────────────────────────────┐
│  HEAD (Anchor Zone)              │  system prompt + first round, never compressed
├──────────────────────────────────┤
│  MIDDLE (Archive Zone)           │  Replaced with LLM-generated summary when threshold exceeded
├──────────────────────────────────┤
│  TAIL (Active Zone)              │  Most recent ~20k tokens, fully preserved
└──────────────────────────────────┘

Trigger thresholds (adjustable in config):

  • 70% context usage → Status bar warning (yellow)
  • 85% context usage → Auto-trigger archival
  • Manual trigger: /compact [focus description]

Tool System

Built-in Tools

Tool Description Permission
ReadFile Read file content, supports line range (limited to cwd / profile directory) Read-only
WriteFile Create or overwrite files (limited to cwd / profile directory) Write
EditFile Precise string replacement; supports replace_all: true for global replacement Write
ListFiles List files using glob patterns Read-only
SearchCode Regex search file content (prefers rg, falls back to grep), global result limit Read-only
RunCommand Execute shell commands, 30s timeout High-risk
WriteNotes Append content to NOTES.md Write
ReadNotes Read current NOTES.md Read-only
CreateTask Create in-session tasks (IDs start from 1, reset after /clear) Write
UpdateTask Update task status, blockedBy, blocks Write
ListTasks List all tasks in the current session Read-only
GetTask Get task details (including dependencies) Read-only
SearchHistory Full-text search historical messages (across all sessions) Read-only
ListSessions List historical sessions (including session chain parent-child relationships) Read-only
WebSearch Search the web via Brave Search; requires search.apiKey in config Read-only

MCP Tool Extensions

Configure MCP servers in config.yaml; tools are auto-registered as mcp__<server_name>__<tool_name>:

mcp_servers:
  github:
    type: stdio
    command: npx
    args: ["@modelcontextprotocol/server-github"]
  filesystem:
    type: stdio
    command: npx
    args: ["@modelcontextprotocol/server-filesystem", "/tmp"]

MCP servers connect in the background in parallel without blocking startup.


Permission System

Modes

Mode Behavior
ask (default) Prompt for confirmation on write operations and shell commands
auto Auto-execute (dangerous commands still require confirmation)

Switch modes: /mode auto or start with --auto.

Permission Confirmation Actions

When a permission dialog appears:

  • Enter / y — Allow this time (default)
  • a — Always allow for this session
  • n — Deny

Safe Project Directory Auto-Approval

When cwd (current working directory) is not a core/sensitive directory, WriteFile and EditFile operations within the directory are auto-approved without confirmation.

Core Directories (still require confirmation):

  • Home directory itself ~ (but ~/projects/foo is safe)
  • Filesystem root / and system trees (/etc, /usr, /bin, etc.)
  • Sensitive subdirectories in home (~/.ssh, ~/.aws, ~/.config, ~/.kube, etc.)

RunCommand is not affected by this rule and always follows the original ask/auto logic.

Dangerous Command Force Confirmation

Regardless of mode, the following commands always trigger confirmation:

rm -rf, git push --force, git reset --hard, sudo, dd if=, mkfs, shutdown, kill -9, etc.

Config Allow/Deny Rules

permissions:
  mode: ask
  allow:
    - ReadFile
    - ListFiles
    - SearchCode
    - "RunCommand(git status)"
  deny:
    - "RunCommand(rm *)"
  disabled_tools:
    - RunCommand     # Completely hidden from the model

Configuration File

File Locations

Path Purpose
~/.memo-agent/config.yaml Global default config
~/.memo-agent/profiles/<name>/config.yaml Config for a specific profile
.env Environment variables in the project root (highest priority)

Full Configuration Example

# Main model configuration
model:
  provider: openai           # openai | custom
  base_url: "${MODEL_BASE_URL}"
  api_key: "${MODEL_API_KEY}"
  name: gpt-4o
  timeout_ms: 60000
  max_tokens: 8192           # Max tokens the model may generate per response

# Auxiliary model (used for context archival compression, recommend a cheaper model)
# If omitted, the main model is used for compression as well
auxiliary:
  provider: openai
  base_url: "${AUX_BASE_URL}"
  api_key: "${AUX_API_KEY}"
  name: gpt-4o-mini
  timeout_ms: 60000
  max_tokens: 4096

# Persistent memory
memory:
  auto_update: true          # Auto-evaluate and write to NOTES.md at end of each round (default on)
  max_inject_tokens: 4000    # Max tokens to inject into system prompt

# Context compression thresholds
context:
  warn_threshold: 0.70       # Warning at 70%
  compress_threshold: 0.85   # Auto-archive at 85%
  tail_tokens: 20000         # Tokens to preserve in the active zone

# Permission control
permissions:
  mode: ask                  # ask | auto
  allow:
    - ReadFile
    - ListFiles
    - SearchCode
    - ReadNotes
    - ListTasks
    - GetTask
    - SearchHistory
    - ListSessions
  deny: []
  disabled_tools: []         # List of completely hidden tools, e.g. [RunCommand]
  sandbox:
    enabled: false           # When true, child processes only see allowed_env_vars
    allowed_env_vars:
      - PATH
      - HOME
      - LANG
      - TERM
      - USER
      - SHELL
      - TZ

# Web search (optional — Brave Search)
search:
  provider: brave
  api_key: "${BRAVE_API_KEY}"
  max_results: 5             # Results per query (1–10)

# MCP servers (optional)
mcp_servers:
  github:
    type: stdio
    command: npx
    args: ["@modelcontextprotocol/server-github"]
    env:
      GITHUB_TOKEN: "${GITHUB_TOKEN}"
  filesystem:
    type: stdio
    command: npx
    args: ["@modelcontextprotocol/server-filesystem", "/tmp"]

Profile Isolation

Use independent configurations, memory, and sessions for different scenarios:

~/.memo-agent/                  # default profile
  config.yaml
  memory/
    NOTES.md
    PROFILE.md
  sessions.db
  recipes/

~/.memo-agent/profiles/work/    # work profile
  config.yaml                    # Can use a different model, API key
  memory/
  sessions.db
  recipes/

Switch profiles:

memo --profile work
memo --profile research

Session Management

# View last 10 sessions
/history

# View last 20 sessions
/history 20

# Full-text search historical messages (/search command used by humans)
/search "sqlite WAL mode"

# Resume a historical session (first use /history to get the session ID)
memo --resume abc12345

# Clear the current session (does not affect NOTES.md)
/clear

The model can also proactively query history via tools:

  • SearchHistory — Full-text search all historical messages, great for "what did we discuss before"
  • ListSessions — List historical sessions, including session chain parent-child relationships (formed automatically after compression/archival)

Directory Structure

memo-agent/
├── src/
│   ├── cli/
│   │   └── index.ts              # Entry: argument parsing, startup flow
│   ├── engine/
│   │   ├── conversationEngine.ts # Core: multi-round session loop, tool invocation
│   │   └── commandRouter.ts      # Slash command routing (pure functions)
│   ├── model/
│   │   ├── client.ts             # OpenAI client factory
│   │   └── streaming.ts          # Streaming response async generator
│   ├── context/
│   │   ├── compressor.ts         # Three-zone archival compression
│   │   ├── tokenBudget.ts        # Token budget tracking and estimation
│   │   └── promptBuilder.ts      # Dynamic system prompt construction
│   ├── memory/
│   │   ├── notesManager.ts       # NOTES.md read/write
│   │   └── profileReader.ts      # PROFILE.md read-only
│   ├── tools/
│   │   ├── registry.ts           # Tool registry (supports disableTools)
│   │   ├── pathUtils.ts          # Shared path security validation
│   │   ├── searchHistory.ts      # Historical message full-text search tool
│   │   ├── listSessions.ts       # Historical session list tool
│   │   └── *.ts                  # Individual tool implementations (self-registering)
│   ├── recipes/
│   │   └── recipeRegistry.ts     # Recipe loading and template expansion
│   ├── session/
│   │   └── db.ts                 # SQLite session storage (WAL + FTS5)
│   ├── permissions/
│   │   └── guard.ts              # Centralized permission decisions
│   ├── mcp/
│   │   └── mcpBridge.ts          # MCP protocol tool bridge
│   ├── config/
│   │   └── loader.ts             # Configuration loading and merging
│   ├── ui/
│   │   ├── App.tsx               # Main UI (state machine)
│   │   ├── MessageList.tsx       # Message list rendering
│   │   └── StatusBar.tsx         # Bottom status bar
│   └── types/
│       ├── messages.ts           # ChatMessage, StreamEvent
│       ├── config.ts             # MemoAgentConfig
│       ├── errors.ts             # MemoAgentError discriminated union
│       ├── tool.ts               # Tool interface
│       └── session.ts            # SessionRow, MessageRow
├── .memo-agent/
│   └── recipes/                  # Project-level recipe files
├── .env.example
├── package.json
├── tsconfig.json
└── prd.md

Tech Stack

Layer Technology
Language TypeScript 5 (strict + ESM)
Terminal UI React 18 + Ink 5
Database better-sqlite3 (WAL mode + FTS5 full-text index)
Model SDK openai (OpenAI-compatible API)
Tool Protocol @modelcontextprotocol/sdk
Config Parsing js-yaml + dotenv
Build tsx (dev) / tsc (production)

Development

# Type check
npm run typecheck

# Development mode (tsx, no build needed)
npm run dev

# Production build
npm run build

# Run the built artifact
npm start

Adding Custom Tools

  1. Create myTool.ts under src/tools/
  2. Implement the Tool interface and call registerTool(myTool) at the end of the file
  3. Add import "./myTool.js" in src/tools/index.ts
import type { Tool, ToolContext, ToolResult } from "../types/tool.js";
import { registerTool } from "./registry.js";

const myTool: Tool = {
  name: "MyTool",
  description: "Describe the tool's purpose",
  inputSchema: {
    type: "object",
    properties: {
      param: { type: "string", description: "Parameter description" },
    },
    required: ["param"],
  },
  maxResultChars: 10_000,
  isReadOnly(): boolean { return true; },
  isEnabled(): boolean { return true; },

  async call(input: Record<string, unknown>, _ctx: ToolContext): Promise<ToolResult> {
    const param = input["param"] as string;
    return { content: `Result: ${param}` };
  },
};

registerTool(myTool);

Security Notes

  • Path Restriction: ReadFile, WriteFile, EditFile only allow operating on files within the current working directory or profile directory; out-of-bounds access returns an error
  • Safe Project Directory: When working in non-core directories (project directories), file write operations are auto-approved; the home directory itself, system paths, and sensitive hidden directories still require confirmation (see Safe Project Directory Auto-Approval)
  • Injection Scanning: NOTES.md, PROFILE.md, and recipe files are automatically scanned for prompt injection signatures before injection; if detected, injection is skipped and a warning is displayed in the UI
  • Command Interception: RunCommand dangerous command blacklist forces confirmation in any mode
  • FTS5 Security: Search queries are automatically escaped to prevent FTS5 syntax injection
  • Tool Masking: Specified tools can be completely removed from the model's view via permissions.disabled_tools
  • Log Sanitization: Runtime warnings are output via UI event stream or stderr without interfering with terminal UI rendering
  • RunCommand Sandbox: When permissions.sandbox.enabled: true, spawned processes inherit only the explicitly listed env vars — API keys and other secrets are stripped from the subprocess environment

Yorumlar (0)

Sonuc bulunamadi