@llipe.com/memo-cli
v1.1.0
Published
Agent-first CLI for capturing and querying development decisions via Qdrant vector store
Readme
memo-cli
Agent-first CLI for capturing and querying development decisions via a Qdrant vector store.
GitHub: https://github.com/llipe/memo-cli
@llipe.com/memo-cli lets AI agents and developers record architectural decisions, integration points, and structural choices during development — then retrieve them semantically at any time.
Table of Contents
- Requirements
- Installation
- Getting Started
- Usage Guide
- Command Reference
- Agent Integration
- Bootstrap Workflow
- Development
- Project Structure
- License
Requirements
| Tool | Version | Notes |
| -------------- | -------- | ---------------------------------------------------------------------------------------------------------------------- |
| Node.js | ≥ 24 LTS | Required for native ESM support |
| Qdrant | ≥ 1.7 | Local Docker or Qdrant Cloud (free tier) |
| OpenAI API key | — | For text embeddings (text-embedding-3-small) |
Installation
From npm (recommended)
npm install -g @llipe.com/memo-cli
memo --versionFrom source
git clone https://github.com/llipe/memo-cli.git
cd memo-cli
pnpm install
pnpm run build
./dist/index.js --helpGetting Started
1. Start Qdrant
Run Qdrant locally with Docker:
docker run -p 6333:6333 qdrant/qdrantOr use Qdrant Cloud (free tier available).
2. Set environment variables
Create a .env file in your project root (or export the vars in your shell):
QDRANT_URL=http://localhost:6333
QDRANT_API_KEY= # leave empty for local unauthenticated Qdrant
EMBEDDINGS_PROVIDER=openai
EMBEDDINGS_API_KEY=sk-... # your OpenAI API key3. Initialize your repository
memo setup initThis launches an interactive wizard that creates a memo.config.json in the current directory, establishing the repository's identity (repo name, organization, domain).
4. Write a decision
memo write \
--rationale "Chose Qdrant over Pinecone for self-hosting flexibility and payload filtering." \
--tags "architecture,storage,qdrant" \
--entry-type decision \
--source agent5. Retrieve it later
memo search "why did we choose the vector database"That's it — the core loop is write decisions → search them later.
Usage Guide
Step 1: Initialize a Repository
Every repository using memo needs a memo.config.json file. The setup command creates it.
Interactive mode (recommended)
memo setup initThe wizard will prompt for:
- Repository name — auto-detected from git remote if available
- Organization — your team or company identifier
- Domain — product area (e.g.,
payments,auth,frontend) - Related repos — other repositories this repo integrates with (optional)
Non-interactive mode (for CI/agents)
memo setup init \
--repo my-service \
--org my-company \
--domain backend \
--relates-to "auth-service,api-gateway"Verify your config
memo setup show # display effective config
memo setup validate # check config validity (exit 0 = valid)Example memo.config.json
{
"schema_version": "1",
"repo": "my-service",
"org": "my-company",
"domain": "backend",
"relates_to": ["auth-service", "api-gateway"],
"defaults": {}
}Step 2: Write Your First Decision
The write command captures a decision and stores it in Qdrant with a vector embedding for semantic retrieval.
Basic write
memo write \
--rationale "Adopted JWT with RS256 for service-to-service auth. Short-lived tokens (15 min) with refresh rotation." \
--tags "auth,jwt,security" \
--entry-type decision \
--source agentAll write flags
| Flag | Required | Default | Description |
| ------------------ | -------- | ----------- | ------------------------------------------------------------------------ |
| --rationale | Yes | — | Decision text (1–5000 chars) |
| --tags | Yes | — | Comma-separated tags (2–5, kebab-case) |
| --entry-type | No | decision | decision | integration_point | structure |
| --source | No | from config | agent | scan | manual |
| --commit | No | — | Associated git commit SHA |
| --story | No | — | Associated story/task identifier |
| --files-modified | No | — | Comma-separated file paths |
| --relates-to | No | — | Comma-separated related repos |
| --on-duplicate | No | — | Duplicate action: consolidate | update | replace | create-new |
| --json | No | false | Output as JSON |
Duplicate detection
If you write an entry with the same repo + commit + story + entry_type + source combination, memo detects the duplicate:
- Interactive (TTY): prompts you to choose an action (consolidate, update, replace, create new)
- Agent/JSON mode: requires
--on-duplicateflag to resolve programmatically
# Agent mode: automatically merge duplicates
memo write \
--rationale "Updated JWT decision to include ECDSA as fallback." \
--tags "auth,jwt,security,ecdsa" \
--entry-type decision \
--source agent \
--commit abc1234 \
--on-duplicate consolidate \
--jsonEntry types explained
| Type | When to use |
| ------------------- | ------------------------------------------------------------------ |
| decision | Architectural or technical decisions made during a task |
| integration_point | How another system, service, or module is integrated |
| structure | Module-level or architectural structure (typically from bootstrap) |
Step 3: Search Decisions
Find decisions using natural language queries. Memo embeds your query and performs semantic vector search against all stored entries.
Basic search
memo search "how do we handle authentication"Search with filters
# Only search within this repo (default)
memo search "database connection pooling" --scope repo
# Include related repos defined in config
memo search "how does the auth service validate tokens" --scope related
# Require specific tags (AND semantics)
memo search "API rate limiting" --tags "api,rate-limit"
# Filter by entry type
memo search "module boundaries" --entry-type structure
# Limit results
memo search "caching strategy" --limit 5
# Combine filters
memo search "event publishing" \
--scope related \
--tags "events,kafka" \
--entry-type integration_point \
--limit 3All search flags
| Flag | Default | Description |
| -------------- | ------- | ----------------------------------------------------------------- |
| --scope | repo | repo (this repo only) or related (include relates_to repos) |
| --tags | — | Comma-separated tags to require (AND semantics) |
| --entry-type | — | Filter: decision | integration_point | structure |
| --source | — | Filter: agent | scan | manual |
| --limit | 5 | Maximum results to return |
| --json | false | Output as JSON |
Reading search results
Human mode output shows:
1. (94%) Adopted JWT with RS256 for service-to-service auth...
repo: my-service tags: auth, jwt, security type: decision
source: agent confidence: high 2026-04-10T15:30:00Z
2. (87%) Auth service exposes /validate endpoint for token...
repo: auth-service tags: auth, api, validation type: integration_point
source: agent confidence: high 2026-04-09T10:00:00ZJSON mode (--json) returns the full machine-readable payload:
{
"query": "how do we handle authentication",
"filters": { "scope": "repo", "repos": ["my-service"] },
"results": [
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"repo": "my-service",
"org": "my-company",
"rationale": "Adopted JWT with RS256...",
"tags": ["auth", "jwt", "security"],
"entry_type": "decision",
"similarity": 0.94,
...
}
],
"count": 2
}Step 4: List Decisions
Browse entries chronologically (newest first) with optional date-range filtering.
Basic listing
memo list # last 20 entries for this repo
memo list --limit 50 # last 50 entriesFilter by date range
# Entries from a specific date
memo list --from 2026-04-01
# Entries in a date range
memo list --from 2026-04-01 --to 2026-04-10
# Full ISO 8601 timestamps also work
memo list --from 2026-04-01T00:00:00Z --to 2026-04-10T23:59:59ZFilter by tags and type
memo list --tags "auth,jwt"
memo list --entry-type decision
memo list --source agent --limit 10All list flags
| Flag | Default | Description |
| -------------- | ------- | ------------------------------------- |
| --scope | repo | repo or related |
| --tags | — | Comma-separated tag filter |
| --entry-type | — | Filter by entry type |
| --source | — | Filter by source |
| --from | — | Start date (YYYY-MM-DD or ISO 8601) |
| --to | — | End date (YYYY-MM-DD or ISO 8601) |
| --limit | 20 | Maximum entries |
| --json | false | Output as JSON |
Step 5: Manage Config
Show effective configuration
memo setup show # human-readable
memo setup show --json # JSON outputValidate configuration
memo setup validate
# Exit code 0 = valid, 1 = errors foundRe-initialize (overwrite existing config)
memo setup init --forceStep 6: Discover Tags
Browse all unique tags stored in your knowledge base, with counts and flexible scope.
List all tags in the current repo
memo tags listScope and sorting options
# Include related repos from config
memo tags list --scope related
# Sort alphabetically (default: frequency)
memo tags list --sort alpha
# JSON output for agent consumption
memo tags list --jsonAll tags list flags
| Flag | Default | Description |
| --------- | ----------- | ---------------------------------------- |
| --scope | repo | repo or related |
| --sort | frequency | frequency (count desc) or alpha |
| --json | false | Output as JSON |
Step 7: Inspect the Knowledge Base
Discover what organizations, repositories, and domains have entries in your Qdrant collection — without any scope restriction.
Show everything
memo inspectOutputs three grouped sections: Organizations, Repositories (with org and domain annotations), and Domains.
Filter to specific facets
# Only repositories
memo inspect --repos
# Only organizations
memo inspect --orgs
# Only domains
memo inspect --domains
# JSON output
memo inspect --jsonAll inspect flags
| Flag | Default | Description |
| ----------- | ------- | ---------------------------------------- |
| --orgs | — | Show only organizations |
| --repos | — | Show only repositories |
| --domains | — | Show only domains |
| --json | false | Output as JSON |
When no filter flags are passed, all three facets are shown.
Step 8: Delete Entries
Safely delete individual entries or bulk-delete by repository or organization. Always confirms before deleting.
Delete a single entry by ID
memo delete --id 550e8400-e29b-41d4-a716-446655440000Memo shows a preview of the matching entry and asks for confirmation.
Bulk delete by repository or organization
# Delete all entries for a repository
memo delete --all-by-repo my-service
# Delete all entries for an organization
memo delete --all-by-org my-companyMemo shows a count of matching entries and asks for confirmation.
Skip confirmation (automation)
memo delete --id <id> --yes
memo delete --all-by-repo my-service --yesAgent mode note
In agent mode (--source agent or when --json is used for single deletes), bulk flags are not available via --json. Single-entry deletion supports --json output:
memo delete --id <id> --json
# outputs: { "deleted": true, "id": "...", "scope": "single", "count": 1 }All delete flags
| Flag | Default | Description |
| ---------------- | ------- | -------------------------------------------------------- |
| --id | — | Delete a single entry by UUID |
| --all-by-repo | — | Delete all entries for the given repo name |
| --all-by-org | — | Delete all entries for the given organization |
| --yes | false | Skip confirmation prompt |
| --json | false | JSON output (single-delete only) |
--id,--all-by-repo, and--all-by-orgare mutually exclusive.
Command Reference
| Command | Purpose | Key Flags |
| --------------------- | ----------------------------- | ------------------------------------------------------------------------------- |
| memo setup init | Create memo.config.json | --repo, --org, --domain, --relates-to, --force |
| memo setup show | Display current config | --json |
| memo setup validate | Check config validity | — |
| memo write | Capture a decision | --rationale, --tags, --entry-type, --source, --on-duplicate, --json |
| memo search <query> | Semantic search | --scope, --tags, --entry-type, --limit, --json |
| memo list | Chronological listing | --from, --to, --tags, --limit, --json |
| memo tags list | Browse unique tags | --scope, --sort, --json |
| memo inspect | Discover orgs/repos/domains | --orgs, --repos, --domains, --json |
| memo delete | Delete entries | --id, --all-by-repo, --all-by-org, --yes, --json |
Global flags
| Flag | Description |
| ----------- | -------------------- |
| --version | Print version number |
| --help | Show help text |
Exit codes
| Code | Meaning |
| ---- | ---------------------------------------------- |
| 0 | Success |
| 1 | User error (bad input, missing config) |
| 2 | System error (Qdrant unreachable, API failure) |
Agent Integration
Memo is designed to be used by AI coding agents as part of their workflow. All commands support --json for machine-readable output.
Recommended agent workflow
# 1. Before starting a task — search for prior decisions
memo search "authentication strategy for microservices" --json
# 2. After completing a task — write the decision
memo write \
--rationale "Implemented OAuth2 with PKCE for the mobile client. Chose this over implicit flow for security." \
--tags "auth,oauth2,mobile" \
--entry-type decision \
--source agent \
--commit "$(git rev-parse HEAD)" \
--story "PROJ-123" \
--on-duplicate consolidate \
--json
# 3. Verify the write
memo search "OAuth2 mobile client" --json | jq '.count'Environment setup for agents
Agents need these environment variables set:
export QDRANT_URL=http://localhost:6333
export EMBEDDINGS_API_KEY=sk-...No .env file needed — agents should inject variables directly into the process environment.
Agent Skill (memo-cli-usage)
This repository ships a reusable agent skill at .github/skills/memo-cli-usage/SKILL.md that teaches AI agents (and developers) how to operate memo-cli correctly and consistently.
The skill is self-contained and installable — copy the memo-cli-usage/ folder into any repository's .github/skills/ directory and reference it from that repo's agent registry.
What the skill covers
| Section | Description |
|---------|-------------|
| When to write / when to search | Precise trigger tables — which moment calls for a memo write, which calls for a memo search first |
| repo, org, domain explained | What each identity field means, how to choose values, and why they matter for scoping |
| relates_to explained | When to add a repo, how cross-repo queries work, and how to avoid over-populating the list |
| Tag strategy | Five-layer taxonomy (domain, technology, entry nature, story ref, scope), naming rules, and ready-made examples |
| Writing quality | The context + decision + rationale formula with side-by-side good/bad examples |
| Intent & outcome entries | How to narrate agent work as it happens — write before starting, write after finishing |
| Recording file changes | How to annotate which files changed and explain why those were the right files |
| Recording config decisions | Env vars, storage layout, feature flags, schema versions — what to capture and why |
| Multi-developer & cross-session | Shared KB, session continuity for stateless agents, multi-day work pattern |
| Memory scope decision tree | When to use IDE/agent memory (/memories/) vs. memo-cli |
| Safe operation guardrails | Non-destructive defaults, --json mode rules, error handling, credential safety |
Install into another repository
# 1. Copy the skill
cp -r .github/skills/memo-cli-usage /path/to/your-repo/.github/skills/
# 2. Register it in your AGENTS.md or skill registry:
# | memo-cli-usage | .github/skills/memo-cli-usage/ | Agent guidance for memo-cli | Any agent |
# 3. Install memo-cli
pnpm add -D @llipe.com/memo-cli
# 4. Initialize the repo
npx memo setup init --repo <name> --org <org> --domain <domain>Once the skill is registered, any agent (GitHub Copilot, Claude, GPT-4, etc.) that loads it will know how to record decisions, restore session context, tag consistently, and stay safe.
Bootstrap Workflow
To populate memo with decisions from an existing codebase, use the bootstrap workflow:
- Feed key artifacts (README, architecture docs, config files) to an AI agent with the bootstrap prompt template
- The agent produces JSON entries conforming to the entry schema
- Validate the JSON with the included validation script
- Write entries via
memo write
See docs/bootstrap-guide.md for the full prompt template, JSON conversion examples, and validation steps.
Quick validation example
# Validate a bootstrap JSON file
node --loader ts-node/esm scripts/validate-bootstrap.ts ./my-bootstrap.jsonDevelopment
Setup
git clone https://github.com/llipe/memo-cli.git
cd memo-cli
pnpm install
cp .env.example .env # configure credentialsScripts
| Script | Description |
| -------------------------- | -------------------------------------------- |
| pnpm run build | Compile TypeScript to dist/ |
| pnpm run build:watch | Compile in watch mode |
| pnpm run typecheck | Type-check without emitting |
| pnpm run lint | ESLint (v9 flat config, strict type-checked) |
| pnpm run lint:fix | ESLint with auto-fix |
| pnpm run format | Prettier format |
| pnpm run format:check | Check formatting without writing |
| pnpm run test | Run Jest test suite |
| pnpm run test:coverage | Run Jest with coverage report |
Testing
pnpm run test # all tests
pnpm run test -- --testPathPattern=write # specific module
pnpm run test:coverage # with coverage report202+ test cases across unit and integration layers. Coverage threshold: 80% lines/functions/statements.
CI/CD
- CI runs on every push: typecheck → lint → test → build → audit
- Publish triggers on semver tag push (
v*.*.*) → npm publish
Project Structure
src/
├── index.ts # CLI entry point (Commander root)
├── commands/
│ ├── setup.ts # memo setup (init / show / validate)
│ ├── write.ts # memo write (with duplicate detection)
│ ├── search.ts # memo search (semantic + pre-filters)
│ ├── list.ts # memo list (chronological + date range)
│ ├── tags.ts # memo tags list (unique tags with counts)
│ ├── inspect.ts # memo inspect (org/repo/domain facets)
│ └── delete.ts # memo delete (safe single + bulk delete)
├── lib/
│ ├── qdrant.ts # Qdrant collection management & queries
│ ├── facets.ts # Scroll-based facet aggregation
│ ├── embeddings.ts # Embeddings adapter interface & factory
│ ├── config.ts # Config file I/O & validation
│ ├── registry.ts # Related-repo resolution
│ ├── output.ts # Human/JSON output formatting
│ ├── errors.ts # Typed error hierarchy
│ ├── dedupe.ts # Deduplication & merge strategies
│ ├── search-filters.ts # Search pre-filter builder
│ ├── list-filters.ts # List pre-filter builder (date range)
│ ├── retry.ts # Exponential backoff retry
│ └── debug.ts # Debug logging (MEMO_DEBUG)
├── adapters/
│ └── openai-embeddings.ts # OpenAI text-embedding-3-small
└── types/
├── entry.ts # EntryPayload Zod schema
├── config.ts # MemoConfig Zod schema
└── cli.ts # Shared CLI interfaces
tests/
├── unit/ # Unit tests (lib, adapters, commands)
└── integration/ # Integration tests (commands, qdrant)
scripts/
├── run-jest.mjs # Jest argument forwarder
└── validate-bootstrap.ts # Bootstrap JSON validator
docs/
├── product-context.md # Product strategy & roadmap
├── technical-guidelines.md # Technical standards
├── system-overview.md # Architecture overview
├── data-model.md # Data entities & schema
├── bootstrap-guide.md # Bootstrap prompt & workflow
└── requirements/
└── prd-001-mvp.md # MVP product requirementsLicense
MIT
