Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .claude-plugin/marketplace.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,14 @@
},
"metadata": {
"description": "Task Journal — append-only reasoning chain memory for AI-coding tasks",
"version": "0.31.2"
"version": "0.32.0"
},
"plugins": [
{
"name": "task-journal",
"source": "./plugin",
"description": "Append-only journal of AI-coding task reasoning chains. Captures hypotheses, decisions, rejections, evidence — renders compact resume packs so an agent can pick up a 2-week-old task with full context.",
"version": "0.31.2",
"version": "0.32.0",
"author": {
"name": "Digital-Threads"
},
Expand Down
58 changes: 58 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,64 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

## [0.32.0] - 2026-11-06

Less noise in the agent's context. Measured on 300 sessions: push-recall was
added to tool results 13,696 times, almost never about the work at hand.

### Changed
- **Push-recall only on a strong match with the session's task.** A hit must be a
rejection or decision the agent or the user recorded (classifier output is not
trusted) on the session's active task or a task of the same module, sharing a
file, issue or commit with the tool call, or at least three meaningful words
(more for a long call) — one shared word used to be enough. Paths count as
files, not words; what an edit writes (`content`, `old_string`, `new_string`)
doesn't count at all; `UTF-8` or `SHA-256` is not an issue key. No session
task, no recall. At most one hit, at most once per ten tool calls of a session
(`TJ_RECALL_EVERY`), never for the journal's own tools. It arrives as
`additionalContext` for every tool: the async hook's `updatedMCPToolOutput`
never reached the model and rewrote other servers' output.
- **The session start is one line.** It names the open task the session most
likely continues — its own after a resume or compaction, else the one the git
branch names (the branch, or an issue key in it), else the folder's latest — and
how to resume it. Resume packs, honesty scores and chronicle gaps are on request
(`task_pack`, `task-journal check`, `module_list`).
- **No chronicle line in replies or prompts.** `task_create` no longer carries a
`chronicle` field, and the mod no longer adds a chronicle reminder to prompts.
- **Short MCP instructions.** Seven plain lines on what to record and why, without
capitals or "NON-NEGOTIABLE".
- **Hooks ship with the plugin.** `plugin/hooks/hooks.json` wires the session start,
push-recall and model switches (`ingest-hook --from-plugin`, never the classifier
queue). `install-hooks` for Claude Code now only takes the hooks earlier versions
wrote out of `settings.json`, after copying it to
`settings.json.task-journal-backup-<time>`, and only once it finds an installed
plugin that ships the hooks; Codex is unchanged. Beside the plugin's hooks (the mod
sets `TJ_PLUGIN_HOOKS`), a hook, `nudge` or `recall-hook` still left in
`settings.json` stands down, and a model switch is recorded once even where both
run (Claude Code without the mod). `--auto-capture` and `--proactive-recall` no
longer apply to Claude Code, and `/rewind` typed in a prompt is no longer recorded
there.
- **The classic nudge runs on a session's first prompt and then every sixth**
(`TJ_NUDGE_EVERY`), not on every prompt, and no longer shouts.
- **Rejections.** The keyword heuristic and `backfill` file a rejection only for an
approach ruled out in so many words ("decided against", "ruled out",
"Rejected: …", "отказались от", "tried X … didn't work"), not for a bug report, a
log line or a test report. Whatever its words, a classified rejection must read
like one: at most 600 characters, no paragraphs, headings, tables or code, not a
question. The classifier drops compaction summaries and notifications, and a raw
tool call unless it is evidence.

### Added
- `task-journal cleanup-noise [--dry-run] [--all] [--yes]` retires what the
classifier once filed as reasoning but is not: raw tool calls (except as
evidence), compaction summaries, harness notifications, and "rejections" that are
whole answers or questions. Each gets a correction stamped with the entry's own
time (the journal stays append-only), which keeps it out of packs and recall
without moving anything in the "newest first" views. A correction cannot be taken
back: `--dry-run` lists every entry in a file, and `--all` writes only with
`--yes`. Only classifier entries and old `backfill` keyword rejections are
touched.

## [0.31.2] - 2026-10-05

### Changed
Expand Down
20 changes: 10 additions & 10 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ members = [
]

[workspace.package]
version = "0.31.2"
version = "0.32.0"
edition = "2021"
rust-version = "1.88"
license = "MIT"
Expand All @@ -20,7 +20,7 @@ categories = ["command-line-utilities", "development-tools"]
[workspace.dependencies]
# `version` must equal workspace.package.version: `cargo publish` uploads it as
# the requirement on core. Cargo can't inherit it; plugin_metadata.rs checks it.
tj-core = { package = "task-journal-core", version = "0.31.2", path = "crates/tj-core", default-features = false }
tj-core = { package = "task-journal-core", version = "0.32.0", path = "crates/tj-core", default-features = false }
anyhow = "1"
thiserror = "1"
serde = { version = "1", features = ["derive"] }
Expand Down
46 changes: 19 additions & 27 deletions INSTALL.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ server) plus thin integrations for each agent:
| Client | What you install | What it gets |
|--------|------------------|--------------|
| Claude Code 2.1.287+ | the plugin (MCP server + skill + mod) | journal tools, the session's task kept in the system prompt, catch-up before compaction, the task above the prompt |
| Claude Code, older | the plugin, optionally `install-hooks` | journal tools, resume packs on session start |
| Codex | `codex mcp add` + `install-hooks --client codex` | journal tools, resume packs, optional auto-capture |
| Claude Code, older | the plugin | journal tools, the open task named at session start, push-recall |
| Codex | `codex mcp add` + `install-hooks --client codex` | journal tools, the open task named at session start, optional auto-capture |
| Any other MCP client | the MCP server | the seven journal tools |

## Prerequisites
Expand Down Expand Up @@ -70,14 +70,20 @@ current (0.30+). If they aren't, it says so once and stays off. On Claude Code
older than 2.1.287 the mod doesn't load; the MCP tools and the skill work as
before.

**Classic hooks next to the mod.** If you ran `task-journal install-hooks`
before, you can keep it. The mod tells those hooks it is active
(`TJ_MOD_ACTIVE=1`), and they skip what the mod replaces — the reminder,
per-message classification (`--auto-capture`) and the transcript catch-ups at
stop, compaction and `/clear` (the mod catches up once, right before each
compaction). The rest keeps running: the session-start resume
pack, the model-switch record, push-recall and `/rewind` corrections. To remove
them anyway: `task-journal install-hooks --scope user --uninstall`.
**Hooks.** The plugin ships its own: at session start, one line naming the
open task the session most likely continues (its own after a resume or a
compaction, else the one the git branch names, else the folder's latest);
after a tool call, push-recall — at most one prior rejection or decision of the
session's task that the call clearly touches, at most once every ten calls; and
the model-switch record. Full packs, honesty scores and chronicle gaps are on
request (`task_pack`, `task-journal check`, `module_list`).

If an earlier version's `task-journal install-hooks` wrote hooks into
`settings.json`, update the plugin, restart Claude Code and run it once more:
for Claude Code it now only takes them out, after copying the file to
`settings.json.task-journal-backup-<time>` — and only once it finds the
installed plugin's hooks. Until then they stand down beside the plugin's hooks,
so no event is handled twice.

### Older Claude Code, or without the plugin

Expand All @@ -91,23 +97,9 @@ Wire the MCP server yourself in `~/.claude/settings.json`:
}
```

and, for resume packs at session start, install the hooks:

```bash
task-journal install-hooks --scope user # → ~/.claude/settings.json
task-journal install-hooks --scope project # → .claude/settings.json
task-journal install-hooks --scope user --auto-capture # also classify prompts and tool calls in the background
```

The default install adds only a read-only `SessionStart` hook (resume packs) and
a `UserPromptSubmit` reminder. `--auto-capture` adds background classification
of prompts, tool calls and session ends; it is a safety net under self-tagging,
not a replacement, and with `--backend hybrid` (the default) it may spawn
`claude -p` for chunks the local heuristic can't classify.

The installer keeps every unrelated key in the settings file, wraps each hook in
`|| true` so a failure never breaks the session, runs the capture hooks `async`
so the chat never waits, and gives `SessionEnd` an explicit timeout.
The hooks come with the plugin, so on older Claude Code install the plugin
too: its hooks run there, only the mod doesn't load. Without the plugin the MCP
tools work on their own.

> The hook payload arrives as JSON on stdin. There are no `$CLAUDE_HOOK_*`
> environment variables.
Expand Down
18 changes: 8 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -101,10 +101,10 @@ that tie it back to the code.

## How it works

- **The mod (Claude Code 2.1.287+).** A plugin of function hooks that runs inside Claude Code and calls the `task-journal` CLI. It keeps the session's active task in the system prompt (a compaction can't drop it), gives each session its own active task, shows the session's task in a band above the prompt (nothing while it has none), reminds the agent to log only after several prompts without an entry, and — right before a compaction — asks the model what was never logged and records it as `suggested` events. It needs no setup. When it runs, the classic hooks skip what it replaces (the reminder, per-message classification and the transcript catch-ups) and keep the rest (resume packs, push-recall, `/rewind`). Codex and Claude Code older than 2.1.287 keep using the hooks below; there the mod simply doesn't load.
- **The mod (Claude Code 2.1.287+).** A plugin of function hooks that runs inside Claude Code and calls the `task-journal` CLI. It keeps the session's active task in the system prompt (a compaction can't drop it), gives each session its own active task, shows the session's task in a band above the prompt (nothing while it has none), reminds the agent to log only after several prompts without an entry, and — right before a compaction — asks the model what was never logged and records it as `suggested` events. It needs no setup. The plugin also ships three hooks of its own: a one-line note at session start naming the open task the session most likely continues, push-recall after tool calls, and the model-switch record. Codex keeps using `install-hooks --client codex`; on Claude Code older than 2.1.287 the mod doesn't load and the plugin's hooks still run.
- **Self-tagging is the primary path (recommended).** You — the agent in the live session — record reasoning directly via the five MCP tools: open a task with a `goal`, append a typed `decision` / `finding` / `rejection` / `evidence` event at the moment of commitment, and `task_close` with a written `outcome`. This is free (it rides the interactive session), language-agnostic, and higher-fidelity than any after-the-fact classifier. The bundled `task-journal` skill drives this automatically. See [MCP tools](#mcp-tools).
- **Auto-capture is an opt-in backstop — OFF by default (v0.14.0).** A fresh `install-hooks` wires only a cheap, read-only SessionStart resume hook: no per-message classifier runs, no `claude -p` is ever spawned, nothing is charged. Self-tagging is the capture mechanism. Opt in with `install-hooks --auto-capture` and Claude Code hooks also run every prompt, tool call, and reply through a two-stage classifier that lands typed events on its own: Stage 1 is a fast in-process heuristic (obvious EN+RU phrasing, zero cost); Stage 2 falls back to an LLM only when the heuristic is uncertain (and only if you pick `--backend agent-sdk` / `api`). Even opted in it is a safety net under your explicit self-tagging, not the main mechanism, and it misses real reasoning — especially non-English prose.
- **Project chronicle (0.31).** The journal is also a map of the system: the project splits into **modules** — parts of the system by meaning, not folders or tickets — and every task belongs to one or more. Each module has a page: how it works now, the decisions, rejections and constraints of all its tasks, and its history, one line per task. A new task can start from that page; closing it adds its line. The journal suggests a module for a new task (from its words and files, no model call) and names what the chronicle is missing — no map yet, tasks without a module, a module whose state lags behind its tasks — at session start and in tool replies, so the agent keeps it up by itself. `/task-journal:map` (or the skill's steps in any client) maps a project and sorts its past tasks, with the user confirming both. A repository has one map: git worktrees share their main checkout's, and a module's history gathers tasks from every worktree, while each task stays in its own worktree's journal.
- **Auto-capture is an opt-in backstop — OFF by default (v0.14.0).** A fresh `install-hooks --client codex` wires only a cheap, read-only SessionStart hook: no per-message classifier runs, no `claude -p` is ever spawned, nothing is charged. Self-tagging is the capture mechanism; on Claude Code the mod adds its catch-up before compaction. Opt in with `install-hooks --client codex --auto-capture` and Codex hooks also run every prompt, tool call, and reply through a two-stage classifier that lands typed events on its own: Stage 1 is a fast in-process heuristic (obvious EN+RU phrasing, zero cost); Stage 2 falls back to an LLM only when the heuristic is uncertain (and only if you pick `--backend agent-sdk` / `api`). Even opted in it is a safety net under your explicit self-tagging, not the main mechanism, and it misses real reasoning — especially non-English prose.
- **Project chronicle (0.31).** The journal is also a map of the system: the project splits into **modules** — parts of the system by meaning, not folders or tickets — and every task belongs to one or more. Each module has a page: how it works now, the decisions, rejections and constraints of all its tasks, and its history, one line per task. A new task can start from that page; closing it adds its line. The journal suggests a module for a new task (from its words and files, no model call) and names what the chronicle is missing — no map yet, tasks without a module, a module whose state lags behind its tasks — when asked: `module_list` and `task-journal state`. `/task-journal:map` (or the skill's steps in any client) maps a project and sorts its past tasks, with the user confirming both. A repository has one map: git worktrees share their main checkout's, and a module's history gathers tasks from every worktree, while each task stays in its own worktree's journal.
- **Artifact extraction.** Each event scans its text for commit hashes, PR URLs, file paths, issue IDs, and branch names. Aggregated artifacts are how Task Journal links related tasks: when you start a new task touching the same issue or file, the prior task is surfaced automatically.
- **Resume packs.** `task_pack` (MCP tool or CLI) renders a task into a compact Markdown briefing — Goal, Outcome, decisions, rejections, evidence, artifacts — that fits in a fresh agent's context window without dumping the raw event log.
- **Auto-capture boundaries.** Beyond per-event capture, two extra hooks mark *reasoning boundaries* automatically. On `PreCompact`, Task Journal reads the transcript JSONL tail (entries newer than the active task's last event) and enqueues anything the synchronous hooks missed before the compact — then drops a marker decision so the post-compact agent sees a clear cut. A `/rewind`-prefixed prompt appends a single correction event so pack readers see where the user rolled back. No mass-rejection of prior events — the boundary is a sentinel, not a rewrite.
Expand Down Expand Up @@ -196,7 +196,8 @@ task-journal pack tj-x9rz1f --mode full
| `doctor` | Self-check the install |
| `rebuild-state` | Rebuild SQLite from JSONL |
| `migrate-project` | Re-key data when a project moves on disk |
| `install-hooks [--scope user\|project] [--auto-capture] [--backend hybrid\|agent-sdk\|api\|heuristic]` | Wire Claude Code hooks. Default: only the read-only SessionStart resume hook. `--auto-capture` adds the per-message classifier (spawns `claude -p` unless `--backend heuristic`). |
| `install-hooks [--client claude\|codex] [--scope user\|project] [--auto-capture] [--backend hybrid\|agent-sdk\|api\|heuristic]` | Codex: wire its hooks (default: the read-only SessionStart hook; `--auto-capture` adds the per-message classifier). Claude Code: its hooks come with the plugin, so this takes the ones earlier versions wrote out of `settings.json`, after a backup. |
| `cleanup-noise [--dry-run] [--all] [--yes]` | Retire what the classifier once filed as reasoning but is not — raw tool calls, compaction summaries, notifications, "rejections" that are whole answers — with one correction each (the journal stays append-only, and a correction cannot be taken back). `--dry-run` lists every entry in a file; `--all` writes only with `--yes`. |

## MCP tools

Expand Down Expand Up @@ -309,15 +310,12 @@ Wire the MCP server into Claude Code (`~/.claude/settings.json`):
}
```

Wire hooks (one-shot). Default installs only the read-only SessionStart resume
hook — no classifier, no `claude -p`:
Claude Code's hooks come with the plugin. Without the plugin the MCP tools work
on their own; there is no hook to wire. If an earlier version's `install-hooks`
left hooks in `settings.json`, take them out (a backup is made first):

```bash
task-journal install-hooks --scope user

# Opt in to per-message auto-capture (spawns `claude -p` per uncertain chunk
# unless you pin --backend heuristic):
task-journal install-hooks --scope user --auto-capture --backend heuristic
```

### Updating
Expand Down
Loading
Loading