Architecture¶
ml-journal is a four-layer system with no background daemons and no external dependencies beyond python3 and git.
Layer diagram¶
judgment layer → Claude skills (extract, classify, construct args)
agent layer → Subagents (isolated context ingestion for heavy synthesis)
mechanical layer → Python scripts (validate, serialize, write)
storage → .project-log/journal.jsonl (per-repo, append-only)
Judgment layer¶
Claude Code skills (/log-entry, /checkpoint, /log-commit, etc.) handle the parts that require reasoning: extracting the right fields from conversation context, classifying entry types, constructing arguments for the mechanical layer.
Agent layer¶
The report-drafter agent is dispatched by /research-report for heavy synthesis that benefits from isolated context. It reads the full journal, git history, and supplementary docs to produce a 9-section draft. The agent never writes files directly — it returns a draft to the skill for confirmation.
Mechanical layer¶
Two stdlib-only Python scripts handle validation and serialization:
journal_log.py— validates fields, constructs the envelope (id,timestamp,type,project,session_id), appends tojournal.jsonljournal_query.py— read operations: status, list, filter, search
The scripts are installed into .project-log/ by /log-init and can be invoked directly from the command line.
Storage¶
journal.jsonl is a plain JSONL file — one JSON object per line, append-only. Each entry has a unique ID, timestamp, type, and session ID. The file is committed to git alongside the code it documents.
Data flow¶
flowchart LR
A[Conversation context] -->|skill extracts fields| B["/log-entry"]
B -->|validates + serializes| C["journal_log.py"]
C -->|appends| D["journal.jsonl"]
D -->|reads| E["journal_query.py"]
D -->|reads| F["/research-report → report-drafter"]
Chain workflows¶
Entry types chain naturally during a session:
flowchart LR
A[Bug identified] -->|auto-propose| B["issue"]
B --> C[Fix verified]
C -->|auto-propose| D["resolution"]
D --> E[Root cause understood]
E -->|auto-propose| F["lesson"]
flowchart LR
A[Hypothesis formed] -->|manual| B["hypothesis"]
B --> C[Experiment run]
C -->|auto-propose| D["experiment"]
D --> E{outcome}
E -->|unexpected| F["discovery"]
E -->|direction confirmed| G["decision"]
Synthesis ladder¶
flowchart TB
J[journal.jsonl] --> S["/log-summarize<br/>prose by type"]
S -->|reused as input| N["/research-note<br/>session-scoped note"]
J -->|end of phase| R["/research-report<br/>dispatches report-drafter"]
R --> RP[RESEARCH_REPORT.md]