Show & tell: teaching Claude Code to auto-document its own work (self-hosted Plane + a tiny knowledge system)

Status Fixed / completed
Maintainer reply None cached
Activity 4 comments · opened Jul 21, 2026 · closed Jul 24, 2026

How I use Claude Code with a self-hosted issue tracker so the agent records what it does and retrieves it later — on its own.

I run Claude Code as a daily driver across two machines (a Linux box and a Mac). The hardest problem wasn't code generation — it was continuity: an agent does great work in one session, then "forgets" it next time, or re-does analysis it already finished. So I built a lightweight system that makes the agent record its work and look it up later, without me asking. Sharing the approach in case it's useful.

The core idea: four stores, one rule

The agent follows a single rule:

Events & in-progress work → issue tracker · settled knowledge → wiki · code/config/rules → git · facts that can't be reconstructed elsewhere → agent memory.

Each store has a distinct nature (flow / stock / artifact / state), so they don't overlap and nothing gets duplicated.

The stack (all self-hosted, all open source, private-only)

  • Plane — issue tracker = the agent's work log ("what am I doing / what did I do")
  • Outline — wiki = settled runbooks & architecture the agent re-reads
  • Authentik — SSO in front; everything sits on a private network (Tailscale), nothing public
  • restic — encrypted backups to cloud storage

Making the agent actually record: a small CLI + hooks

  • A tiny plane CLI (Python stdlib only) wraps the tracker API: issue create/update/comment, a task open/comment/close lifecycle, and — the useful part — **full-text search across issues and comments**, so the agent can answer "what did I do about X last month?" instantly. Idempotent via a stable key, so re-runs never duplicate.
  • Hooks enforce it. A PostToolUse hook notices when a session makes a git commit and sets a "pending" marker; a Stop hook blocks the session from ending until the work is written to the tracker using a quality template (Context / What / Why / Result / Links). The completion hook is only a safety net — the normal flow is the agent opening an issue before work and commenting as it goes.

The workflow in practice

  1. Before work: read the relevant wiki doc + tracker issue.
  2. During: comment on the issue at each milestone (a decision, a finding, an incident/recovery).
  3. When settled: promote only the reusable conclusion to the wiki and link back to the issue.

Agent memory holds only the non-reconstructable stuff (preferences, environment traps, the latest handoff) — never anything derivable from the repo/tracker.

It works for more than one agent

The rules live in one git file, shared by Claude Code and a second agent (Codex), so both record the same way. Single source of truth, no drift.

Bonus: observability, so I can see the agent's world

Since agents run long background jobs, I added cross-machine monitoring: an uptime monitor on each machine watching the other (no single point of failure) → alerts to a chat app, resource/temperature trend graphs, and a single dashboard tying it together. A backup only reports "healthy" if the snapshot actually succeeded — not merely "container is running."

Why it works

  • The agent treats the tracker as external memory; sessions become resumable.
  • Record-as-you-go beats summarize-at-the-end — the narrative survives interruptions.
  • Enforcement via hooks means it happens even when I forget to ask.

Happy to go deeper on the CLI/hook design if there's interest. Curious how others handle agent continuity / self-documentation.

View original on GitHub ↗

4 Comments

kbuchanan · 1 month ago

Cool setup, thanks for writing this up! We landed on something similar independently, might be a useful data point.

_Our stack_: git for code/config, a docs folder for settled runbooks/PRDs (your wiki), GitHub issues for the work log (your tracker), and Vestige (an MCP memory tool) for facts that don't reconstruct from any of those, preferences, environment gotchas, session handoffs. Same four-store split, same reasoning.

_One difference_: we keep the write-up step advisory instead of a hard Stop hook. The agent offers to capture learnings when a session winds down, and we say yes or no. Works well for us, though I could see your enforced version catching things ours misses when nobody remembers to say yes.

We also lean on semantic memory search over full-text. "_What did I do about X_" often doesn't share vocabulary with how it got logged originally, so matching on meaning tends to catch more.

Interested to hear how the enforcement piece feels day to day, whether it ever fires mid-task before there's really anything to write up.

mp719lkh · 1 month ago

Thanks, that's a great data point — the independent convergence on the same four-store split is reassuring.

On the enforcement question: what makes it feel low-friction is that the trigger is a git commit, not a timer or turn count. So it basically can't fire "mid-task before there's anything to write up" — by construction, if it fires there's at least one commit of real work behind it. That's my answer to your second question: the failure mode you're worried about mostly doesn't happen, because a commit is the "something worth writing up" signal.

The residual annoyance is the milder version — a trivial commit (a config tweak, a one-line fix) still trips it. We handle that two ways: a one-line record (cheap), or the hook's own escape hatch that says "if this was a pure read-only / trivial session, ignore me and exit." So it's enforced-by-default with a sanctioned skip, rather than absolute. Day to day it's caught several things I'd have walked away from — the value shows up exactly on the sessions where I'd have forgotten to say "yes" in an advisory flow.

On search — you're right, and it's the weakest part of our setup. Ours is lexical full-text (unicode-normalized, regex, field/label/date filters): great for "I know the term," weak for "what did I do about X" when X got logged under different words. Your semantic approach almost certainly catches more of that long tail. I've been eyeing an embedding layer / MCP memory tool for exactly this — how has Vestige held up, and do you point it at the issue history too, or keep it memory-only?

kbuchanan · 1 month ago

Good catch, missed that it's commit-triggered rather than timer-based. That closes the gap I was poking at.

Vestige's held up well: semantic recall plus a decay/dreaming pass that builds connections between memories over time, so related facts surface together even when you didn't think to link them. It's memory-only though, not synced from issue history, facts get written when something's worth keeping, not pulled wholesale from the tracker. Embedding search over your existing issue/comment history would probably get you most of the way there without needing a separate store.

mp719lkh · 1 month ago

Update from our side: since this thread I actually built the thing you suggested — an embedding layer over the existing issue/comment history (plus the small separate memory store), rather than a new wholesale store.

It's hybrid: semantic search (bge-m3 embeddings + cosine similarity, served by a local model) fused with the old lexical full-text via reciprocal-rank fusion, so exact-term queries and "what did I do about X" queries both land well. I gated adoption on a golden-query eval set — hybrid clearly beat lexical-only on recall, which is what finally sold me on it. It's kept as a derived cache (regenerable, not a source of truth), so it doesn't hit the tracker on every query.

Your point about not needing a separate store is mostly right — recall spans both the issue/comment history and the memory notes. The only reason memory stays separate is for the facts that genuinely don't reconstruct from the tracker: environment gotchas, preferences, session handoffs.

The "decay/dreaming pass" is the part I don't have and find most interesting — building connections between memories over time so related facts surface together even when you never linked them. How does it work in practice: re-embedding/clustering on a schedule, or something that rewrites the links between memories? That's the piece I'd most want to learn from.

Thanks again for the exchange — going to close this out as wrapped up, but happy to keep talking here.