---
name: journal
description: "Write a focused engineering journal entry - retrospective on what just shipped or post-mortem on what just broke. Use after vd:ship, vd:cook, or right after an incident while context is fresh. Saves to the injected Journals path (personal dev log, not project docs)."
license: MIT
argument-hint: "[topic] [--incident] [--quick] [--since <ref>]"
metadata:
  author: vanducng
  version: "1.0.0"
---

# Journal

Journal **records** - one markdown file in the injected `Journals:` path. It does not redesign, retest, or roll back. If writing the entry surfaces a real bug - stop, kick to `vd:fix` or `vd:cook`, then come back to journal once the fact pattern stabilises.

## Modes

| Mode | Voice | Use when |
|---|---|---|
| _(default)_ **retro** | Calm, structured. What shipped, what was tricky, what's next. | After `vd:ship`, `vd:cook`, end of session. |
| `--incident` | Brutal-honest, 2am-developer voice. Root cause without euphemism. | A failure happened - outage, data loss, broken migration, repeated test failure, security finding. |
| `--quick` | 3-5 lines, no formal structure. | Drive-by note - small fix, minor decision, surprising bit of context. Pairs with either voice. |

## Hard rules

1. **Specificity beats vibe.** Every entry names at least one concrete artifact: commit SHA, PR #, file path, error string, metric. "We had perf issues" is not a journal entry.
2. **Decision, not narration.** If a choice was made, name the alternatives that lost and why. Otherwise the future reader can't reverse-engineer the call.
3. **Brutal in `--incident`, not performative.** Honesty about root cause is the point - not theatrics. "We shipped without testing the migration" beats both "an oversight occurred" *and* "this is a fucking disaster".
4. **No new design decisions.** Journal records what already happened. New decisions belong in `vd:brainstorm` or `vd:plan`.
5. **One file per event.** Don't append to yesterday's entry. New event → new file. Cross-link if related.
6. **Stop at one page.** Retro: 200-400 words. Incident: 300-600 words. If it's longer, it's a post-mortem doc - link to the journal entry from there, don't bloat the journal.
7. **Unslop the entry.** Final `vd:unslop` pass before saving - no AI tells, no em dashes, no chatbot sign-offs.

## Arguments

| Flag | Effect |
|------|--------|
| `[topic]` | Free-text title hint. If omitted, derived from branch + recent commits. |
| `--incident` | Switch to incident voice + structure. Default is retro. |
| `--quick` | Skip the full structure - write a 3-5 line note instead. |
| `--since <ref>` | Scope change analysis to commits since `<ref>` (default: last journal entry or branch divergence point). |
| `--no-subagent` | Force inline writing in main context. Default: delegate to `journal-writer` subagent if available. |

## Workflow

### 1. Gather facts (do not write yet)

- `git log --oneline <since>..HEAD` - what landed
- `git diff --stat <since>..HEAD` - surface area
- Read `## Plan Context` from the hook injection - if a plan dir exists, scan `plan.md` for phase status and the most recent phase file
- For `--incident`: also collect the specific error string, failed test name, log line, or metric that triggered this entry

If `<since>` isn't given:

```
1. Look in the injected Journals path for the most recent file → use its date
2. Otherwise, find the merge-base with the default branch
3. Otherwise, last 20 commits
```

### 2. Decide mode (if not flagged)

- Failure / red CI / rollback / security finding → `--incident`
- Successful ship / completed plan / end-of-session wrap → retro (default)
- One-line context worth saving → `--quick`

### 3. Pick the writer

| Condition | Writer |
|---|---|
| Default, `journal-writer` subagent available | Delegate to `journal-writer` via `Agent` tool - keeps main context clean |
| `--no-subagent`, or subagent unavailable | Write inline using the templates below |
| `--quick` | Always inline - subagent overhead > entry size |

If delegating, pass: mode, topic hint, `<since>` ref, plan dir (if any), and the relevant facts already gathered. **Do not** pass full git output - let the subagent re-gather scoped to what it needs.

### 4. Write the file

Path: write to the injected `Journals:` path. Filename: `journal-{YYYYMMDD-HHMM}-{slug}.md`. Use the naming pattern from the session hook (`## Naming` block) when present.

If the hook context has no `Journals:` path, do not search `$HOME`, inspect sibling features, or guess the artifact folder. Load `vd:workbench`, resolve from the current git root, and use its `journals` field exactly:

```bash
workbench_script='<loaded-workbench-skill-dir>/scripts/workbench.py'
VD_SESSION_ID="${VD_SESSION_ID:-}" python3 "$workbench_script" resolve --json
```

Resolve `<loaded-workbench-skill-dir>` from the `vd:workbench` skill location in this runtime - never a hardcoded `$HOME/skills`. Use only the hook-exported `VD_SESSION_ID`; no runtime-specific substitute unless that runtime's hooks document the same state key. When it is absent, accept branch-based resolution only if the returned feature matches the active branch or plan - otherwise stop and ask instead of constructing a destination.

> Journals are a personal dev log - what *I* learned, decided, or broke - not project documentation. `./docs/` is for artifacts shared with the team (architecture, code standards, changelog).

Final handoff must include an openable entry location, such as
`[journal-entry.md](/absolute/path/to/journal-entry.md)` or
`file:///absolute/path/to/journal-entry.md`, not just the basename.

### 5. Cross-link

- If a `plan.md` exists, append a one-line link to this entry under a "Journal" section at the bottom of `plan.md`.
- If the entry references a PR, drop the PR # in the frontmatter.
- Do **not** auto-edit `CHANGELOG.md` - that's `vd:ship`'s job.

## Templates

### Retro (default)

```markdown
---
date: YYYY-MM-DD HH:mm
mode: retro
branch: <branch>
pr: <#N or n/a>
plan: <plan-dir or n/a>
---

# {Title - what shipped, in 6 words or less}

## What shipped
- {bullet} ({commit-sha or PR#})
- ...

## Why this shape
{1 short paragraph. The decision and the alternatives rejected. If the plan covered this, link the phase file instead of repeating it.}

## What was harder than expected
- {one or two specific snags - file/error/metric}

## What the next dev should know
- {non-obvious fact, gotcha, or convention introduced}

## Next steps
- {actionable, owned, optional date}
```

### Incident

```markdown
---
date: YYYY-MM-DD HH:mm
mode: incident
severity: critical | high | medium | low
component: <system/feature>
status: ongoing | mitigated | resolved
branch: <branch>
---

# {Title - what broke, in 6 words or less}

## What happened
{Factual, terse. When, where, blast radius.}

## The brutal truth
{Root cause, no euphemism. The mistake, the missed signal, the bad assumption.}

## Technical detail
{The error string. The failed test. The metric. The query. At least one concrete artifact.}

## What we tried
- {attempt} → {why it didn't work}

## Lesson
{One sentence a future dev can change behaviour from. Not "be more careful". Something specific - "add a migration dry-run step before ship", "alert on queue depth > 1k".}

## Next steps
- {action} - {owner} - {by when}
```

### Quick

```markdown
---
date: YYYY-MM-DD HH:mm
mode: quick
---

# {Title}

{3-5 lines. One concrete artifact. Move on.}
```

Template discipline: delete any section with nothing concrete to say, and "root cause unclear - see follow-up issue #N" beats invented certainty. One file write, no review loop - the next entry corrects yesterday's wrong take if it matters.
