### Clone Repository and Setup Development Environment Source: https://github.com/askenter/claude-journal-tools/blob/main/README.md Clone the Claude Journal Tools repository, set up a Python virtual environment, install pytest, and run the test suite. ```bash git clone git@github.com:askenter/claude-journal-tools.git cd claude-journal-tools python3 -m venv venv && venv/bin/python -m pip install pytest virtualenv/bin/python -m pytest tests/journal/ ``` -------------------------------- ### Install Required Tools (RHEL/Oracle/Fedora) Source: https://github.com/askenter/claude-journal-tools/blob/main/skills/journal/references/setup.md Installs git, git-crypt, and gh on RHEL-based systems using dnf. Requires sudo privileges. ```bash sudo dnf install git git-crypt gh ``` -------------------------------- ### Setup Claude Journal Data Repository Source: https://github.com/askenter/claude-journal-tools/blob/main/docs/setup.md Initiates the setup process for the Claude Journal data repository. This command handles tool checks, git identity configuration, and gh authentication. ```bash /journal setup ``` -------------------------------- ### Install Required Tools (macOS) Source: https://github.com/askenter/claude-journal-tools/blob/main/skills/journal/references/setup.md Installs git, git-crypt, and gh on macOS using Homebrew. Ensure Homebrew is installed first. ```bash brew install git git-crypt gh ``` -------------------------------- ### Install Required Tools (Debian/Ubuntu) Source: https://github.com/askenter/claude-journal-tools/blob/main/skills/journal/references/setup.md Installs git, git-crypt, and gh on Debian/Ubuntu systems using apt. Requires sudo privileges. ```bash sudo apt install git git-crypt gh ``` -------------------------------- ### Install Claude Journal Plugin Source: https://github.com/askenter/claude-journal-tools/blob/main/docs/setup.md Installs the Claude Journal plugin from the marketplace. This registers necessary hooks and the /journal command. ```bash /plugin marketplace add askenter/claude-journal-tools /plugin install claude-journal@claude-journal-tools ``` -------------------------------- ### Install git-crypt Source: https://github.com/askenter/claude-journal-tools/blob/main/docs/setup.md Installs the git-crypt tool, which is required for encrypting the data repository. Choose the command appropriate for your operating system. ```bash # macOS: brew install git-crypt # Debian/Ubuntu: sudo apt-get install -y git-crypt # RHEL/Oracle: sudo dnf --enablerepo=ol9_developer_EPEL install -y git-crypt ``` -------------------------------- ### Add New-Skill Acceptance Handling Source: https://github.com/askenter/claude-journal-tools/blob/main/docs/plans/2026-06-08-skill-proposals.md Implement the logic for accepting new skill proposals. This includes parsing proposal details, installing the skill locally and on other devices, updating the data repository (CHANGELOG.md and skills/INDEX.md), and removing the entry from the proposal file. ```markdown - For new-skill proposals: 1. Parse `scope`, `target`, the skill `` (from the heading), the one-line `description` (from the fenced skill's frontmatter), and the `provenance` line. Extract the `SKILL.md` body from inside the four-backtick fence. 2. Write that body to `~/claude-journal/` (create parent dirs). If a skill named `` already exists there, show the user and ask before overwriting. 3. Mirror it onto this device so no manual install is needed β€” copy the whole skill directory: - `scope: global` β†’ `~/.claude/skills//` - `scope: project:` β†’ `~/.claude/projects//.claude/skills//` Other devices receive it via their next SessionStart `sync_skills` sync. (Claude Code enumerates skills at session start, so an accepted skill is invocable from the next session.) 4. Record the acceptance in the data repo by hand, in two files (`` = UTC date, e.g. `date -u +%F`): - append one line to `~/claude-journal/CHANGELOG.md`: ` +skill accepted /` - in `~/claude-journal/skills/INDEX.md`, find the row whose Skill = `` and Scope = `` and change its Status from `proposed` to `accepted`, setting Updated = ``. If no such row exists (proposal predates the manifest, or the file is missing), create the manifest from the header below and add: `| | | accepted | | | |` 5. Remove this new-skill entry from the proposal file. ``` -------------------------------- ### SessionStart Hook Output Example Source: https://github.com/askenter/claude-journal-tools/blob/main/docs/reference.md The SessionStart hook can return context to Claude by writing JSON to stdout. This JSON includes hook-specific details and additional context. ```json { "hookSpecificOutput": { "hookEventName": "SessionStart", "additionalContext": "πŸ““ …pending proposals…" } } ``` -------------------------------- ### Install git-crypt on macOS Source: https://github.com/askenter/claude-journal-tools/blob/main/README.md Installs the git-crypt package on macOS using Homebrew. ```bash brew install git-crypt ``` -------------------------------- ### Install git-crypt on Debian/Ubuntu Source: https://github.com/askenter/claude-journal-tools/blob/main/README.md Installs the git-crypt package on Debian or Ubuntu systems. ```bash sudo apt-get install -y git-crypt ``` -------------------------------- ### Session Start Hook Execution Source: https://github.com/askenter/claude-journal-tools/blob/main/docs/data-flow.md The `on_start.py` script runs automatically when a new session begins. It pulls journal updates, synchronizes memories and skills, builds proposal context, and emits additional context for Claude. This hook ensures Claude has the latest information and pending proposals. ```shell SessionStart event payload (stdin JSON): { cwd, … } β”‚ β–Ό β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ 1. pull_journal() git pull --rebase --autostash β”‚ β”‚ failed? β†’ remember it (STALE warning later) β”‚ β”‚ 2. sync_all_memories(): β”‚ β”‚ memories//*.md β†’ ~/.claude/projects//memory/ β”‚ β”‚ Β· skips type: feedback memories (those are proposals) β”‚ β”‚ Β· appends NEW MEMORY.md index lines; never deletes yours β”‚ β”‚ 3. sync_all_skills(): β”‚ β”‚ skills/global// β†’ ~/.claude/skills// β”‚ β”‚ skills/projects/

// β†’ ~/.claude/projects/

/.claude/ β”‚ β”‚ skills// β”‚ β”‚ 4. build_proposal_context(cwd): β”‚ β”‚ list pending proposals/-.md entries β”‚ β”‚ 5. emit hookSpecificOutput.additionalContext (stdout JSON): β”‚ β”‚ [STALE warning?] + [LOCKED warning?] + [proposal list?] β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ β–Ό Claude's next turn sees the additionalContext as a system reminder: "πŸ““ claude-journal has pending proposals for this project: … Run /journal accept | skip | edit" ``` -------------------------------- ### Manual Setup for Journal Consolidator Routine Source: https://github.com/askenter/claude-journal-tools/blob/main/README.md This bash command manually creates the journal consolidator routine. It requires specifying environment variables for secrets and the repository clone URL. ```bash claude -p --bare \ --allowedTools "Bash,Read" \ "/schedule create a nightly routine named 'journal-consolidator' \ that runs at 03:30 in my local timezone. The routine prompt is the \ contents of ~/claude-journal/consolidator/ROUTINE.md. It needs the \ environment variables GIT_CRYPT_KEY_B64 set to and GH_TOKEN \ set to , and before running should clone the private repo \ over HTTPS with the token: git clone https://x-access-token:\$GH_TOKEN@github.com//.git (the same token then authenticates its push)." ``` -------------------------------- ### Run Pytest for on_start Hook Failure Source: https://github.com/askenter/claude-journal-tools/blob/main/docs/plans/phase1.md Execute the pytest suite for the on_start hook to verify its expected failure. This command is used after writing the failing test to confirm the initial setup before implementation. ```bash PYTHONPATH=. venv/bin/pytest tests/journal/test_on_start.py -v ``` -------------------------------- ### New Skill Proposal Entry Format Source: https://github.com/askenter/claude-journal-tools/blob/main/docs/reference.md Example of a new skill proposal entry within a proposal markdown file. This format includes metadata like kind, scope, target, provenance, and rationale, followed by the skill's markdown content. ```markdown ## New skill: - **kind:** new-skill - **scope:** global # or project: - **target:** skills/global//SKILL.md - **provenance:** distilled from 2 sessions on 2026-06-05, 2026-06-07 - **rationale:** FENCE4 markdown --- name: description: --- FENCE4 ``` -------------------------------- ### Initialize Journal Device Source: https://github.com/askenter/claude-journal-tools/blob/main/docs/reference.md Set up a new device for the first time. This script clones the data repository, unlocks git-crypt, and records the device name. You can specify the repository URL and journal path if defaults are not suitable. ```python python3 tools/journal/init_device.py ``` ```python python3 tools/journal/init_device.py --repo-url --journal-path ``` ```python python3 tools/journal/init_device.py --register-hooks # manual (non-plugin) only ``` -------------------------------- ### Run Journal Device Initialization Script Source: https://github.com/askenter/claude-journal-tools/blob/main/docs/plans/phase1.md Bash script to execute the Python `init_device.py` module. It sets up the environment and runs the script with provided arguments. ```bash #!/usr/bin/env bash set -euo pipefail HERE="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" exec "${HERE}/venv/bin/python" -m tools.journal.init_device "$@" ``` -------------------------------- ### Verify SessionStart Hook Execution Source: https://github.com/askenter/claude-journal-tools/blob/main/docs/plans/phase1.md Tests the on_start.py hook to ensure it runs without errors and that the local repository is up-to-date. ```bash echo '{"session_id":"smoke","cwd":"/home/you/myproject"}' | \ PYTHONPATH=/home/you/myproject \ /home/you/myproject/venv/bin/python /home/you/myproject/tools/journal/hooks/on_start.py ``` -------------------------------- ### Configure a new device for Claude Journal Source: https://github.com/askenter/claude-journal-tools/blob/main/README.md On each device, set the repository URL and initialize the tools. This script clones the repository if it doesn't exist, attempts to unlock it with the provided key, and records the device name. The git-crypt key should be placed in ~/.claude/journal/git-crypt.key. ```bash export CLAUDE_JOURNAL_REPO_URL="git@github.com:/claude-journal.git" # On the device that ran the bootstrap, the repo already exists locally and # is unlocked. On *additional* devices, place the key first (out-of-band): mkdir -p ~/.claude/journal && chmod 700 ~/.claude/journal install -m 600 /dev/stdin ~/.claude/journal/git-crypt.key # paste key, then Ctrl-D # Clones the repo if missing, attempts the git-crypt unlock, records the name: git clone git@github.com:askenter/claude-journal-tools.git ~/claude-journal-tools python3 ~/claude-journal-tools/tools/journal/init_device.py "$(hostname -s)" ``` -------------------------------- ### Run Journal Device Unit Tests Source: https://github.com/askenter/claude-journal-tools/blob/main/docs/plans/phase1.md Command to execute unit tests for the `init_device.py` script. This verifies the functionality of the initialization process. ```bash PYTHONPATH=. venv/bin/pytest tests/journal/test_init_device.py -v ``` -------------------------------- ### Accepting a New Skill Proposal Source: https://github.com/askenter/claude-journal-tools/blob/main/skills/journal/references/resolve.md Steps for accepting a new skill proposal, including parsing, writing, mirroring, and recording in the data repository. ```bash echo "$(date -u +%F) +skill accepted ${scope}/${name}" >> ~/claude-journal/CHANGELOG.md # Find and update the skill's row in INDEX.md, or create it if it doesn't exist. # Example of adding a new row if it doesn't exist: # echo "| ${name} | ${scope} | accepted | ${description} | ${provenance} | $(date -u +%F) |" >> ~/claude-journal/skills/INDEX.md ``` -------------------------------- ### Bootstrap Journal Repository (Local-Only) Source: https://github.com/askenter/claude-journal-tools/blob/main/skills/journal/references/setup.md This command initiates the bootstrap process for the journal repository without cloning from a remote origin. The user must run this command themselves. ```bash $TOOLS/scripts/bootstrap-journal-repo.sh --no-remote ``` -------------------------------- ### Breadcrumb JSON Schema Example Source: https://github.com/askenter/claude-journal-tools/blob/main/docs/specs/cognitive-consolidation-design.md An example of the JSON structure for a session breadcrumb, including structural fields and synthesized fields from the Haiku call. The synthesized fields are omitted if the Haiku call fails. ```json { "session_id": "0a7e6abf-4198-4441-ab11-9e95d603dc63", "device": "laptop", "project": "-home-you-myproject", "started_at": "2026-04-28T09:14:32Z", "ended_at": "2026-04-28T10:02:18Z", "files_touched": [ "src/api.py", "frontend/components/ChatInput.tsx" ], "skills_invoked": ["superpowers:brainstorming"], "first_prompt": "Help me design a memory consolidation pipeline...", "session_summary": "Designed a multi-device memory consolidation pipeline with tiered auto-apply.", "decisions": [ "Use a private claude-journal repo as the central store", "Tier-3 CLAUDE.md edits go through inline confirm, not auto-apply" ], "facts_learned": [ "Claude routines run on Anthropic infrastructure, not the local box" ], "open_questions": [ "Where should /journal accept|skip|edit live: project-local or global?" ] } ``` -------------------------------- ### Get Flushed Sessions Path Source: https://github.com/askenter/claude-journal-tools/blob/main/docs/superpowers/specs/2026-06-09-on-demand-consolidation-design.md This function returns the path to the device-local file storing flushed session IDs. ```python flushed_sessions_path() -> Path # ~/.claude/journal/flushed-sessions ``` -------------------------------- ### Opening Proposal File for Editing Source: https://github.com/askenter/claude-journal-tools/blob/main/skills/journal/references/resolve.md Opens a proposal file in the default editor for user edits. ```bash ${EDITOR:-nano} ``` -------------------------------- ### Update Claude Journal Plugin Source: https://github.com/askenter/claude-journal-tools/blob/main/README.md Use these commands to update the Claude Journal plugin. Refreshing the marketplace alone does not upgrade the installed plugin. ```text /plugin marketplace update claude-journal-tools /plugin update claude-journal@claude-journal-tools ``` -------------------------------- ### System Overview: Device Synchronization via Data Repository Source: https://github.com/askenter/claude-journal-tools/blob/main/docs/architecture.md Diagram showing how devices sync data through a central, encrypted Git repository, with a separate consolidator routine also interacting with this repository. ```text DEVICE A (e.g. laptop) DEVICE B (e.g. workstation) β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ Claude Code + plugin β”‚ β”‚ Claude Code + plugin β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ SessionStart hook ─pull─┐ β”‚ β”‚ β”Œβ”€pull─ SessionStart hook β”‚ β”‚ (sync + surface) β”‚ β”‚ β”‚ β”‚ (sync + surface) β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ Stop hook ───push──┐ β”‚ β”‚ β”‚ β”‚ β”Œβ”€β”€push─── Stop hook β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”‚β”€β”€β”€β”€β”‚β”€β”€β”€β”˜ β””β”€β”€β”€β”‚β”€β”€β”€β”‚β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ β”‚ β”‚ β”‚ push β”‚ β”‚ pull pull β”‚ β”‚ push β–Ό β”‚ β”‚ β–Ό β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ DATA REPO (git host) β”‚ β”‚ github.com//claude-journal β”‚ β”‚ private Β· git-crypt encrypted β”‚ β”‚ raw/ digests/ memories/ skills/ β”‚ β”‚ proposals/ state/ consolidator/ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β–²β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ clone + β”‚ β”‚ produces digests/, unlock + β”‚ β”‚ memories/, skills/, push β”‚ β”‚ proposals/ β”‚ β–Ό β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ PHASE 2 β€” CONSOLIDATOR ROUTINE β”‚ β”‚ Claude Code /schedule routine β”‚ β”‚ runs in Anthropic's cloud β”‚ β”‚ ONCE PER ACCOUNT, nightly β”‚ β”‚ prompt = consolidator/ROUTINE.md β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ ``` -------------------------------- ### CLAUDE.md Proposal Reminder Source: https://github.com/askenter/claude-journal-tools/blob/main/docs/specs/cognitive-consolidation-design.md This is an example of a system reminder block injected by the hook on the next SessionStart in an affected project, indicating a pending proposal. ```text πŸ““ claude-journal has 1 proposal from 2026-04-28: myproject/CLAUDE.md (lines 47-52): replace "Swarm" with "Docker Compose" Rationale: 4 sessions this week deployed via compose; deploy.sh has no swarm commands. Reply "/journal accept", "/journal skip", or "/journal edit" ``` -------------------------------- ### Breadcrumb JSON Structure Source: https://github.com/askenter/claude-journal-tools/blob/main/docs/reference.md Example of the JSON format used for session breadcrumbs. This includes session metadata, files touched, and skills invoked. ```json { "session_id": "abc123", "device": "laptop", "project": "-home-you-myproject", "started_at": "2026-06-08T09:12:33+00:00", "ended_at": "2026-06-08T09:40:01+00:00", "files_touched": ["/home/you/myproject/main.py"], "skills_invoked": ["code-review"], "first_prompt": "help me refactor the auth module" } ``` -------------------------------- ### Initialize Device for Journal Tools Source: https://github.com/askenter/claude-journal-tools/blob/main/skills/journal/references/setup.md This command initializes a new device for the Claude Journal Tools. It requires setting the CLAUDE_JOURNAL_REPO_URL environment variable and running the script with a device name. The script also offers to enable plugin auto-update for the device. ```bash tools/journal/init_device.py ``` -------------------------------- ### Buffer Format Example Source: https://github.com/askenter/claude-journal-tools/blob/main/docs/data-flow.md Illustrates the JSON structure used for buffering data, where each line represents a single JSON object containing breadcrumb and transcript information. ```json {"breadcrumb": { …structural fields… }, "transcript": "## User\n\n…"} ``` -------------------------------- ### Initialize Device for Claude Journal Source: https://github.com/askenter/claude-journal-tools/blob/main/docs/setup.md Initializes a device for use with Claude Journal. This involves setting the repository URL, handling the git-crypt key, and cloning the tools repository. ```bash export CLAUDE_JOURNAL_REPO_URL="git@github.com:/claude-journal.git" # On ADDITIONAL devices, place the git-crypt key first (out-of-band): mkdir -p ~/.claude/journal && chmod 700 ~/.claude/journal install -m 600 /dev/stdin ~/.claude/journal/git-crypt.key # paste key, then Ctrl-D # Clone (if missing), attempt git-crypt unlock, record the device name: git clone git@github.com:askenter/claude-journal-tools.git ~/claude-journal-tools python3 ~/claude-journal-tools/tools/journal/init_device.py "$(hostname -s)" ``` -------------------------------- ### Transcript Markdown Format Source: https://github.com/askenter/claude-journal-tools/blob/main/docs/reference.md Example of the markdown format for session transcripts. It includes user and assistant prose, with tool calls and results omitted. Secret redaction is applied. ```markdown ## User help me refactor the auth module ## Assistant Sure β€” let's start by … ``` -------------------------------- ### Make Script Executable Source: https://github.com/askenter/claude-journal-tools/blob/main/docs/plans/phase1.md Command to grant execute permissions to the `init-journal-device.sh` script. ```bash chmod +x scripts/init-journal-device.sh ``` -------------------------------- ### Initialize Journal Device with a Specific Name Source: https://github.com/askenter/claude-journal-tools/blob/main/docs/plans/phase1.md Command to run the journal device initialization script, specifying a unique name for the device (e.g., 'bot_dev1'). ```bash ./scripts/init-journal-device.sh bot_dev1 ``` -------------------------------- ### Unlock the Encrypted Data Repository Source: https://github.com/askenter/claude-journal-tools/blob/main/docs/setup.md Use this command sequence to unlock the encrypted data repository if it appears locked. This involves creating a directory, setting permissions, installing the git-crypt key, and then running the unlock command within the repository. ```bash mkdir -p ~/.claude/journal && chmod 700 ~/.claude/journal install -m 600 /dev/stdin ~/.claude/journal/git-crypt.key # paste key, Ctrl-D git-crypt unlock ~/.claude/journal/git-crypt.key # run inside ~/claude-journal ``` -------------------------------- ### Claude Journal Tools Decision Flow Source: https://github.com/askenter/claude-journal-tools/blob/main/docs/agents.md Use this flowchart to determine the correct action based on your current need within the Claude Journal Tools project. It guides you through checking past work, handling proposals, and executing commands. ```text Need a fact about past work / this project? β†’ check ~/claude-journal/memories// (and digests/) not raw/. If absent, ask the user. See a "pending proposals" reminder? β†’ tell the user; act only when they run /journal accept|skip|edit. Asked to set up the pipeline? β†’ /journal setup Asked to schedule the nightly routine? β†’ /journal schedule Asked to consolidate now / not wait for the nightly run? β†’ /journal consolidate Tempted to grep ~/claude-journal/raw/ ? β†’ stop. That's the consolidator's input, not your source. ``` -------------------------------- ### Initialize Journal Package Source: https://github.com/askenter/claude-journal-tools/blob/main/docs/plans/phase1.md Empty __init__.py file for the tools.journal package, indicating it is a Python package. ```python # tools/journal/__init__.py """Cognitive consolidation pipeline: per-device hook utilities.""" ``` -------------------------------- ### Enable Auto-Update for Journal Tools Plugin Source: https://github.com/askenter/claude-journal-tools/blob/main/skills/journal/references/setup.md This command enables the auto-update feature for the journal tools plugin by merging a setting into the user's settings file. It is idempotent and safe to re-run. The output indicates whether auto-update was enabled, already on, or if the installation is manual. ```bash python3 "$TOOLS/tools/journal/autoupdate.py" ``` -------------------------------- ### SessionStart Hook Entrypoint Source: https://github.com/askenter/claude-journal-tools/blob/main/docs/plans/phase1.md Entrypoint for the SessionStart hook. Pulls the claude-journal repository to ensure the device has the latest changes. Logs errors to a buffer file if they occur. ```python # tools/journal/hooks/on_start.py """SessionStart hook entrypoint. Pulls claude-journal so this device sees other devices' work. Phase 1 is pull-only; Phase 2 adds memory/skill sync; Phase 3 adds proposal surfacing.""" import json import sys from datetime import datetime, timezone from pathlib import Path from tools.journal.paths import journal_repo_path from tools.journal.pull import pull_journal def _read_payload_safe() -> dict: try: return json.loads(sys.stdin.read()) except Exception: return {} def main() -> int: try: _ = _read_payload_safe() # payload not used in Phase 1 pull_journal(journal_repo_path()) except Exception as exc: try: log = Path.home() / ".claude" / "journal-buffer.log" log.parent.mkdir(parents=True, exist_ok=True) with open(log, "a", encoding="utf-8") as f: f.write(f"[{datetime.now(timezone.utc).isoformat()}] on_start error: {exc!r}\n") except Exception: pass return 0 if __name__ == "__main__": sys.exit(main()) ``` -------------------------------- ### Bootstrap New Journal Repository Source: https://github.com/askenter/claude-journal-tools/blob/main/docs/reference.md Use this script to create and initialize a new data repository for your journal. It can create a remote GitHub repository or initialize locally only. Ensure all preconditions are met before execution. ```bash scripts/bootstrap-journal-repo.sh --repo /claude-journal # create remote + push ``` ```bash scripts/bootstrap-journal-repo.sh --no-remote # local-only ``` -------------------------------- ### Bootstrap Journal Repository (Remote) Source: https://github.com/askenter/claude-journal-tools/blob/main/skills/journal/references/setup.md This command initiates the bootstrap process for the journal repository, cloning it from the remote origin. The user must run this command themselves. ```bash $TOOLS/scripts/bootstrap-journal-repo.sh --repo /claude-journal ``` -------------------------------- ### Create and Seed GitHub Repository Source: https://github.com/askenter/claude-journal-tools/blob/main/docs/plans/phase1.md Creates a private GitHub repository, clones it locally, sets up the directory structure, adds a README, and commits the initial state. ```bash gh repo create askenter/claude-journal --private --description "Personal Claude knowledge consolidation hub" git clone git@github.com:askenter/claude-journal.git ~/claude-journal cd ~/claude-journal mkdir -p raw digests memories skills/global skills/projects proposals consolidator/prompts touch CHANGELOG.md # .gitkeep so empty directories are tracked find . -type d \( -name raw -o -name digests -o -name memories -o -name proposals \ -o -path './skills/global' -o -path './skills/projects' \ -o -path './consolidator/prompts' \) -exec touch {}/.gitkeep \; cat > README.md <<'EOF' # claude-journal Personal knowledge consolidation hub. Auto-populated by Claude Code hooks on each device and (eventually) a nightly Claude routine. Do not edit manually unless you know what you are doing. Design spec: specs/cognitive-consolidation-design.md EOF git add . && git commit -m "init: bootstrap claude-journal layout" git push -u origin main ``` -------------------------------- ### Initialize Device for Journal Pipeline Source: https://github.com/askenter/claude-journal-tools/blob/main/docs/plans/phase1.md Python script to set up a device for the journal pipeline. It ensures the journal repository is cloned, writes the device name, creates symlinks for hooks, and registers these hooks in the Claude Code settings. ```python import argparse import json import os import subprocess import sys from pathlib import Path def register_hooks_in_settings( *, settings_path: Path, on_stop_path: Path, on_start_path: Path, ) -> None: """Insert the journal hooks into Claude Code's settings.json idempotently.""" if settings_path.exists(): data = json.loads(settings_path.read_text()) else: data = {} settings_path.parent.mkdir(parents=True, exist_ok=True) hooks = data.setdefault("hooks", {}) for event, path in (("Stop", on_stop_path), ("SessionStart", on_start_path)): groups = hooks.setdefault(event, []) if not groups: groups.append({"hooks": []}) existing_cmds = {h.get("command") for g in groups for h in g.get("hooks", [])} if str(path) in existing_cmds: continue groups[0]["hooks"].append({"type": "command", "command": str(path)}) settings_path.write_text(json.dumps(data, indent=2) + "\n") def _ensure_journal_clone(repo_url: str, target: Path) -> None: if target.exists() and (target / ".git").exists(): return target.parent.mkdir(parents=True, exist_ok=True) subprocess.run(["git", "clone", repo_url, str(target)], check=True) def _write_device_name(device: str) -> None: p = Path.home() / ".claude" / "journal" / "device-name" p.parent.mkdir(parents=True, exist_ok=True) p.write_text(device + "\n") def _symlink(src: Path, dst: Path) -> None: dst.parent.mkdir(parents=True, exist_ok=True) if dst.is_symlink() or dst.exists(): dst.unlink() dst.symlink_to(src) def main(argv: list[str] | None = None) -> int: parser = argparse.ArgumentParser(description="Initialize this device for the journal pipeline.") parser.add_argument("device", help="Stable name for this device (e.g., laptop, workstation).") parser.add_argument( "--repo-url", default="git@github.com:askenter/claude-journal.git", help="claude-journal git URL.", ) parser.add_argument( "--journal-path", default=str(Path.home() / "claude-journal"), help="Local path for the claude-journal clone.", ) args = parser.parse_args(argv) project_root = Path(__file__).resolve().parents[2] on_stop_src = project_root / "tools" / "journal" / "hooks" / "on_stop.py" on_start_src = project_root / "tools" / "journal" / "hooks" / "on_start.py" on_stop_dst = Path.home() / ".claude" / "hooks" / "journal-on-stop.py" on_start_dst = Path.home() / ".claude" / "hooks" / "journal-on-start.py" _ensure_journal_clone(args.repo_url, Path(args.journal_path)) _write_device_name(args.device) _symlink(on_stop_src, on_stop_dst) _symlink(on_start_src, on_start_dst) register_hooks_in_settings( settings_path=Path.home() / ".claude" / "settings.json", on_stop_path=on_stop_dst, on_start_path=on_start_dst, ) print(f"journal device '{args.device}' initialized.") return 0 if __name__ == "__main__": sys.exit(main()) ``` -------------------------------- ### Push with Offline Buffering Logic Source: https://github.com/askenter/claude-journal-tools/blob/main/docs/data-flow.md Outlines the step-by-step process for pushing data with offline buffering, ensuring resilience against network issues or interruptions. It details the order of operations for draining buffers, writing files, staging changes, committing, pulling, and pushing, with fallback to buffering on failure. ```markdown push_breadcrumb: 1. drain_buffer() ── re-apply any backlogged entries first 2. write raw///.json 3. write raw///.transcript.md (if transcript non-empty) 4. git add -A raw/ state/ 5. git diff --cached --quiet? dirty β†’ git commit -m "raw: " clean β†’ skip commit (avoids "nothing to commit" wedge) 6. git pull --rebase --autostash --quiet ── merge other devices first 7. git push β”‚ β”œβ”€ all steps ok β†’ return True └─ any failure β†’ append to buffer, return False (retried next session) ``` -------------------------------- ### Initialize Journal Tests Package Source: https://github.com/askenter/claude-journal-tools/blob/main/docs/plans/phase1.md Empty __init__.py file for the tests.journal package, indicating it is a Python package. ```python # tests/journal/__init__.py ``` -------------------------------- ### Run Surface Proposals Test File Source: https://github.com/askenter/claude-journal-tools/blob/main/docs/plans/2026-06-08-skill-proposals.md Execute the pytest command to run the `test_surface_proposals.py` file. This verifies that both new and existing tests pass, ensuring the proposal surfacing functionality works as expected. ```bash venv/bin/python -m pytest tests/journal/test_surface_proposals.py -q ``` -------------------------------- ### Manual Bootstrap Data Repo Source: https://github.com/askenter/claude-journal-tools/blob/main/docs/setup.md Manually bootstraps the Claude Journal data repository. This involves cloning the tools repository and running a script to set up the journal repo. ```bash git clone git@github.com:askenter/claude-journal-tools.git ~/claude-journal-tools ~/claude-journal-tools/scripts/bootstrap-journal-repo.sh --repo /claude-journal ``` ```bash # local-only (wire the remote yourself later): … --no-remote ``` -------------------------------- ### Building Proposal Context String Source: https://github.com/askenter/claude-journal-tools/blob/main/docs/plans/2026-06-08-skill-proposals.md This Python function constructs a formatted string to display pending proposals for a given project. It lists proposals with their labels and associated file paths, providing instructions for user interaction. ```python def build_proposal_context(*, journal_repo: Path, cwd: str) -> Optional[str]: """Return the additionalContext string to surface, or None if there are no pending proposals for this project.""" project_key = project_key_from_cwd(cwd) proposals = _list_proposals_for_project(journal_repo / "proposals", project_key) if not proposals: return None lines = [ "πŸ““ claude-journal has pending proposals for this project:", "", ] for path in proposals: text = _read_text(path) entries = _iter_entries(text) if not entries: summary = _first_nonempty(text) or path.name lines.append(f"- [proposal] {summary} (`{path}`)") continue for heading, body in entries: label = _entry_label(heading, body) lines.append(f"- [{label}] {heading} (`{path}`)") lines.extend([ "", "These are new skills, behavioral rules, or CLAUDE.md edits the " "consolidator extracted from recent sessions. They are NOT " "auto-applied.", "", "Run `/journal accept`, `/journal skip`, or `/journal edit` to " "review and act on them.", ]) return "\n".join(lines) ``` -------------------------------- ### Plan Journal Consolidation Source: https://github.com/askenter/claude-journal-tools/blob/main/skills/journal/references/consolidate.md Run the planner to flush the current session, pull the repository, check for unlocks, and identify dates needing consolidation. This command mirrors the routine's `force-date` functionality when a specific date is provided. ```bash python3 "$TOOLS/tools/journal/consolidate.py" plan ``` ```bash python3 "$TOOLS/tools/journal/consolidate.py" plan 2026-06-09 ``` -------------------------------- ### Test Offline Backlog Behavior (Fill Buffer) Source: https://github.com/askenter/claude-journal-tools/blob/main/docs/plans/phase1.md Simulates a Git push failure by setting an invalid remote URL, then runs the Stop hook to test buffer filling. ```bash cd ~/claude-journal git remote set-url origin git@github.com:invalid/invalid.git echo "$PAYLOAD" | PYTHONPATH=/home/you/myproject \ /home/you/myproject/venv/bin/python /home/you/myproject/tools/journal/hooks/on_stop.py cat ~/.claude/journal-buffer.jsonl | head -5 ``` -------------------------------- ### Stage and Commit Changes Source: https://github.com/askenter/claude-journal-tools/blob/main/tools/journal/templates/ROUTINE.md Stages specified directories and CHANGELOG.md for commit. Assumes git repository is already set up. ```bash git add digests/ memories/ proposals/ skills/ CHANGELOG.md ``` -------------------------------- ### Hooks Configuration Source: https://github.com/askenter/claude-journal-tools/blob/main/docs/reference.md The hooks.json file defines event handlers for different lifecycle events, such as SessionStart and Stop. Hooks can be configured to run specific commands. ```json { "hooks": { "SessionStart": [ { "hooks": [ { "type": "command", "command": "python3 \"${CLAUDE_PLUGIN_ROOT}/tools/journal/hooks/on_start.py\"" } ] } ], "Stop": [ { "matcher": "", "hooks": [ { "type": "command", "command": "python3 \"${CLAUDE_PLUGIN_ROOT}/tools/journal/hooks/on_stop.py\"" } ] } ] } } ```