Code journal

~4 min read

Code journal

A daily engineering log that auto-summarises your git activity into structured notes.

What it does

Every morning, a schedule drops a > [!ai] directive into a fixed journal note. The connected agent picks the directive up (via pending_directives), runs git against your repos with its own tooling, and writes up yesterday’s activity:

Setup

1. The schedule

A schedule rule does exactly one thing: at the chosen time it splices > [!ai] <prompt> into the target note. It does not run an agent itself — there is no cron, no agent: block, no provider/model/mode, and no enable_bash. The actual git work is done by whatever MCP agent is connected (it brings its own shell access), which sees the directive and acts on it.

# .lettuce/schedules.yml
- daily: "07:00"
  target: "Code/Journal inbox.md"
  prompt: |
    Generate today's code journal note at Code/<today>.md.

    For each repo I track (~/code/lettuce, ~/code/website, ~/code/garden-blog),
    ignoring *.lock, node_modules/, and .build/:
    1. git log --since "yesterday 00:00" --until "yesterday 23:59"
       --pretty=format:"%h %s"
    2. git log --since ... --until ... --stat (file changes)
    3. For each commit: capture hash, message, timestamp; if the message
       contains [decision], extract it as a decision; if changed files add
       lines containing TODO:, capture them.

    Write Code/<today>.md with this shape:

    ---
    title: "Code journal <today>"
    date: <today>
    tags: [journal, code]
    ---

    # <today>

    ## Lettuce (12 commits over 4 hours)

    Highlights:
    - Shipped 0.6.0 (`a1b2c3d`)
    - Added Suggestions mode (`d4e5f6g`)
    - Notarised the DMG (`h7i8j9k`)

    ### Commits

    - `a1b2c3d` Ship 0.6.0
    - `d4e5f6g` Add Suggestions mode
    - ... (full list)

    ### Notable files
    - Sources/LettuceServer/MCP.swift (+200 / -34)
    - Tests/LettuceKitTests/SuggestionsTests.swift (+412 / -0)

    ### Decisions

    - Picked propose-only as the new agent default (commit message tag [decision]).

    ### TODOs added

    - `Sources/LettuceServer/MCP.swift:412` — handle stale-base for batch edits

    Then write the journal file. Overwrite if it already exists (idempotent).

The Code/Journal inbox.md target is just a note that collects the daily directives; the agent reads them and creates the dated journal files. The poller fires the schedule once a minute while lettuce serve (or the app) is running.

Why it’s useful

Variations

Each variation is a separate entry in .lettuce/schedules.yml, again just {daily/weekly, prompt, target}. The connected agent does the git/gh work and writes the dated file; spell out the date arithmetic in the prompt (there is no {{ }} templating).

Per-repo journals

- daily: "07:00"
  target: "Code/Journal inbox.md"
  prompt: |
    Generate today's code journal at Code/lettuce/<today>.md focused only on ~/code/lettuce.

Useful when you only care about one repo and want signal-rich notes.

Live counter

A schedule only fires at a single daily/weekly time — there is no per-hour or cron expression — so check in at a couple of points in the day with separate entries:

- daily: "12:00"
  target: "Code/Journal inbox.md"
  prompt: |
    Update today's daily note Daily/<today>.md: set a `commits-today: N` frontmatter key
    to the output of `git log --since "today 00:00" --oneline | wc -l` across my repos.

Gives you a midday “I did N things today” counter in your daily note.

Pull request rollups

- weekly: "Monday 09:00"
  target: "Code/Journal inbox.md"
  prompt: |
    Run `gh pr list --state merged --search "merged:>$(date -v-7d +%F)"
    --json title,url,body,mergedAt` and build a PR digest at
    Code/PR digest <this-week>.md.