Skip to content

Agent Journal

An agent journal is a structured decision log that lives in a private GitHub repo. It records the decisions, directions, and philosophies behind a project. Both humans and AI coding agents can propose entries. Only the doraval CLI writes to the remote.

When a change conflicts with a recorded principle (or you just want to capture a useful note), the journal can push back (for decisions) or simply record tagged notes.

Decisions get lost across Slack threads, commit messages, and agent sessions that start fresh with no memory. An agent makes reasonable choices that accidentally contradict deliberate ones.

The journal is a persistent memory with opinions. It doesn’t block; it argues.

The journal has two layers:

Remote: A private GitHub repo (e.g., saif-shines/saif-shines.md) with global.md for universal principles and projects/<name>.md for project-specific decisions.

Local: doraval maintains a cache at ~/.doraval/, not in the project directory. No submodules, no symlinks, no config files polluting your repos.

~/.doraval/
├── config.yml # Journal repo + project mappings
├── journals/ # Cached journal files
│ ├── global.md
│ └── doraval.md
└── pending/ # Proposed entries awaiting sync
└── doraval/

Register everything (journal + the coding agent dora should use on the fly when you later run journal add) with the recommended top-level command:

Terminal window
dora init

(You can still use the more focused doraval journal init if you only want the journal part.)

journal init is designed to be low-friction:

  • It detects a sensible default for your journal repo from the current git remote (preferred) or your active GitHub account.
  • It shows you where the default came from before prompting.
  • It remembers the journal repo you used previously, so subsequent projects are faster.
  • Fully scriptable via --repo / --project flags or DORAVAL_JOURNAL_REPO / DORAVAL_PROJECT environment variables.

The command stores the mapping in ~/.doraval/config.yml (never in your project) and fetches the journal files locally. No per-project config files, submodules, or symlinks are required.

## Use "drift" not "score" for rubric deviation
​```yaml
pushback: 7
tags: [naming, cli]
author: human
date: 2026-05-25
status: active
​```
We renamed `score` to `drift` because "score" implies a generic quality
rating. The command measures deviation from a rubric, distance from a
standard, not a grade.
FieldDescription
pushback1–10. How hard the journal argues if violated.
tagsTags for categorization (decisions or notes): naming, cli, architecture, testing, ux, api, docs.
authorhuman or agent:<name>.
dateISO date.
statusactive, superseded, or retired.
superseded_by(Optional) Title of the replacing entry.
RangeLabelWhat it means
1–3Nudge”This diverges slightly. Probably fine, just be aware.”
4–6Friction”This contradicts a deliberate decision. Reconsider.”
7–10Wall”Core philosophy conflict. Override explicitly or update the journal.”

Even pushback 10 is an argument, not a gate.

Two-stage hybrid approach:

  1. Tag filter (cheap): Match the current action’s domain against entry tags. Fast and deterministic.
  2. Semantic check (matches only): For entries that pass the filter, the human (v1) or agent (v2) judges whether the change actually contradicts the principle.

Agents and humans propose entries. Only doraval journal sync writes to the remote. No race conditions.

Human/Agent → doraval journal add → ~/.doraval/pending/ → doraval journal sync → GitHub

sync publishes pending entries to the remote and refreshes your local cache. (Advanced maintenance features like projects/_index.md and auto-archiving older entries are planned but not yet implemented.)

Terminal window
doraval journal init # One-time setup: register project + link to journal repo
doraval journal list # View active principles for the current project
doraval journal update # Pull the latest from the remote GitHub repo into local cache
doraval journal add # Propose a decision/note or capture long rich markdown (--raw-markdown) (stages locally)
doraval journal sync # Publish pending entries + refresh cache
Terminal window
# Start of a session or before using journal-aware tools
doraval journal update
# Explore current principles
doraval journal list
# Capture a decision you just made
doraval journal add "Always use 'update' not 'refresh' for cache pulls" \
--pushback 6 \
--tags cli,docs
# At the end of the session (or when ready to share)
doraval journal sync

update keeps the local ~/.doraval/journals/ mirror fresh. sync always refreshes first, then publishes anything in pending/.

journal check and Principle drift integration into skill drift / validate are the major remaining pieces (see the implementation plan).

For a clear explanation of the mental model and why the journal is built this way, see How the Agent Journal Works.

See the individual command pages under Commands (e.g. journal init, journal update) for flag details and examples.

  • doraval skill drift gains Principle drift: flags when a skill contradicts an active journal entry (planned).
  • doraval eval / skill judge can be extended in the future to incorporate journal entries as additional context for the LLM judge.
  • Entries with pushback >= 7 surface as warnings in doraval skill validate (planned).
  • Not an AGENTS.md replacement. AGENTS.md says how to work. The journal says why decisions were made.
  • Not a changelog. Principles and reasoning, not a list of changes.
  • Not a linter. Opinions with conviction levels, not pass/fail rules.
  • Not a blocker. Every pushback can be overridden, but the conflict must be acknowledged.