AI agents live in the present tense. They start fresh every session, lose context between tasks, and have no reliable way to record what they noticed, felt uncertain about, or figured out. private-journal-cli gives your agent a private, local journal — a place to write structured thoughts, capture project notes, and search prior context without going through MCP or any external service.
Everything stays on your machine. No sync, no cloud, no transport friction — just a plain CLI your agent can call directly from any runtime that can execute a local binary.
- Highlights
- Installation
- Agent Skill
- Quick Start
- Storage Model
- Command Reference
- Output and Exit Codes
- Development
- Local-only journaling and search — nothing leaves the machine
- Project and user journals kept separate by default
- Timestamped Markdown entries with YAML frontmatter
- Sidecar
.embeddingfiles for semantic retrieval --jsonoutput for automation and agent workflows
Install from npm:
npm install --global private-journal-cli
private-journal helpRun without a global install:
npx private-journal-cli helpUse from a local clone before publishing:
npm install
npm run build
npm link
private-journal helpA ready-made agent skill is bundled in skills/private-journal-cli.skill. Install it so your agent runtime (Claude Code, Codex, Cursor, etc.) automatically knows when and how to use private-journal:
# From this repo
npx skills add ./skills/private-journal-cli.skill
# Or once published to npm
npx skills add private-journal-cli@skillThe skill teaches agents to:
- capture structured thoughts with
thoughts(preferred overwrite) - always pass
--jsonfor machine-readable output - search prior entries before writing new ones
- route project notes vs. personal insights to the correct journal
Write a freeform project journal entry:
private-journal write \
--content "I finally untangled the TypeScript build issue" \
--jsonCapture structured thoughts. --project-notes is written to the project journal; the other sections go to the user journal:
private-journal thoughts \
--project-notes "The CLI dispatcher should stay dependency-free" \
--technical-insights "Command handlers are easier to test than process wrappers" \
--feelings "Relieved that the transport migration is small" \
--jsonSearch across project and user journals:
private-journal search \
--query "times I was frustrated with TypeScript" \
--type both \
--limit 5 \
--jsonRead a specific entry by path:
private-journal read \
--path /absolute/path/to/.private-journal/2026-03-13/14-30-45-123456.md \
--jsonList recent entries:
private-journal recent \
--days 7 \
--limit 10 \
--type both \
--json- Project entries default to
.private-journal/in the current working directory when that location is usable. - User entries default to
~/.private-journal/. - Override either location with
--journal-path <path>or--user-journal-path <path>. - Search and recent listing read from both journals by default.
Example layout:
.private-journal/
2026-03-13/
14-30-45-123456.md
14-30-45-123456.embedding
~/.private-journal/
2026-03-13/
14-32-15-789012.md
14-32-15-789012.embedding
Each entry is stored as Markdown with YAML frontmatter:
---
title: "2:30:45 PM - March 13, 2026"
date: 2026-03-13T14:30:45.123Z
timestamp: 1773412245123
---
## Technical Insights
Command handlers are easier to test than transport-specific wrappers.Write a freeform project journal entry.
Options:
--content <text>entry body--journal-path <path>override the project journal root--user-journal-path <path>override the user journal root--jsonemit JSON output
Write structured thought sections. project_notes is stored in the project journal. feelings, user_context, technical_insights, and world_knowledge are stored in the user journal.
Options:
--feelings <text>--project-notes <text>--user-context <text>--technical-insights <text>--world-knowledge <text>--journal-path <path>--user-journal-path <path>--json
Search entries semantically.
Options:
--query <text>--limit <number>--type project|user|both--sections section1,section2--journal-path <path>--user-journal-path <path>--json
Read an entry by path.
Options:
--path <absolute-or-relative-path>--json
List recent entries.
Options:
--days <number>--limit <number>--type project|user|both--journal-path <path>--user-journal-path <path>--json
- Add
--jsonto any command for machine-readable output. - Exit code
0means success. - Exit code
1means CLI usage or validation error. - Exit code
2means an unexpected runtime failure.
You can wire private-journal into Claude Code's Stop hook so every agent session automatically writes a project note when Claude finishes a response.
Copy docs/hooks/journal-stop.js to ~/.claude/hooks/journal-stop.js, then register it in ~/.claude/settings.json:
{
"hooks": {
"Stop": [{ "hooks": [{ "type": "command", "command": "node \"/Users/you/.claude/hooks/journal-stop.js\"" }] }]
}
}Design notes:
- Always exits
0— a journal failure never blocks Claude - Writes to the project journal (
cwd/.private-journal), keeping entries scoped to the repo - Silently skips if
private-journalis not on$PATH - Trims
last_assistant_messageto 800 chars — enough context without bloat
npm run build
npm test
npm run devJesse Vincent jesse@fsck.com
MIT