/log — append a journal entry
SkillDocs & knowledgeLog is a skill that lets your AI record new AI experiments and produce a report in the terminal. Once added, your agent can log each experiment you run and give you a terminal report, so you have a clear record of your AI work.
Use /log — append a journal entry in Claude, ChatGPT or Ahel Desktop
Free. Sign in, add /log — append a journal entry and connect your AI. About a minute.
Also: Claude Code · Cursor · Codex
Then ask your AI: use the /log skill
Details
Instructions available. Your AI can read the instructions. Execution depends on the setup they require.
Account requirements not reviewed. Check the skill instructions before use; Ahel provides instructions and does not run this skill.
No other account needed.
Add the skill, then ask your AI to log an experiment. It will record it and show a report in your terminal.
What your AI can do with it
- Log a new AI experiment
- Get a report in the terminal after logging
- Keep a record of your AI experiments
- Review experiment details in a terminal report
What this skill tells your AI
The instructions your AI receives, as published by jellyrock/jellyrock in .claude/skills/log/SKILL.md and read by Ahel’s review.
Contract
Goal. Be the single capture entry point for every kind of journal write JellyRock keeps, so instead of remembering which file each entry lives in and which format it uses, you type /log <type> <body> and the skill routes to the right journal with the right format. It covers four types: decision (agent-routed to a numbered ADR in docs/adr/ or a sub-ADR note in docs/decisions.md), followup (docs/progress.md open followups), signal (docs/signals-backlog.md upstream version-watch rows), and running (the ## Currently running in-flight cursor in docs/progress.md). There are two capture modes. Mechanical types (followup, signal, running) apply directly via Edit — no per-invocation gate, because routing is mechanical and the corrective loop for systematic wrongness is /audit-skill log, not a confirmation prompt every session. The decision type is the deliberate exception and the one flow where the agent does classification work: it drafts the record, applies a significance gate (architectural / hard-to-reverse / cross-component?), and routes it — ADR-grade → a new numbered ADR in docs/adr/, sub-architectural → a note in docs/decisions.md, trivia → declined — then surfaces a diff-and-confirm the human can override in one tap. Here the gate is right because the agent is confirming a significance + routing judgment, not gating a mechanical append; the human classifies nothing. This is the sole sanctioned write path for those three journals; raw Write/Edit on them is not permitted (per the root AGENTS.md capture-discipline rule). The mechanical path is light, but the decision flow's significance judgment is a plausible-wrong call, so the skill is pinned at the Sonnet tier with effort: low.
Inputs. The arguments are <type> [optional title or body] — the first whitespace-separated token is the type; the rest is passed to the type-specific flow. The recognized types are listed once, in the Implementation; a sub-agent capture sentence spells out exactly that list, and nothing else restates it. If there are no arguments or the type isn't recognized, the skill lists the valid types and asks; it never guesses.
Outputs.
- For a mechanical
/log(followup/signal/running): the append (or cursor replacement) applied directly via Edit to the target journal, plus thelast-updated:frontmatter bump ondocs/progress.md/docs/signals-backlog.mdso the staleness banner stays accurate. - For
/log decision: depending on the agent's significance verdict, either a new numbered ADR (docs/adr/NNNN-<slug>.mdin the house style, plus its row in thedocs/adr/README.mdindex table) for an ADR-grade decision, or a slug-based sub-ADR note appended todocs/decisions.md(append-only — never insert mid-file or rewrite older notes, except via--revise=<slug>, which corrects a note that misdescribes what shipped) for a sub-architectural one, or a one-line decline for trivia — with any supersede-chain update applied to the superseded record. Surfaced as a diff-and-confirm before writing, with the proposed routing shown for one-tap override. - A
npm run lint:docspass after the write, confirming the journal's schema + staleness gate. - The skill is pure local-file edits — no commit (the user owns that), no remote calls, no service restarts.
Success criteria.
- Mechanical captures (
followup,signal,running) are applied directly via Edit — no per-invocation diff-then-confirm gate. Trust the skill; if outputs go systematically wrong, run/audit-skill logto fix the SKILL.md (git reset --soft HEAD~1recovers a rare bad capture). Per-invocation confirmation is the wrong corrective loop for systematic issues — it adds friction every session and masks the problem the audit would catch. - The
decisiontype is the one exception to the no-gate rule — it surfaces a diff-and-confirm because it's confirming a significance + routing judgment (does this clear the decision-discipline bar? does it supersede an existing slug?), not gating a mechanical append. - For
/log decision, the agent applies the significance gate itself and the human classifies nothing. ADR-grade decisions (architectural / hard-to-reverse / cross-component) become numbered ADRs indocs/adr/; sub-architectural ones (non-obvious rationale / closes off alternatives / a constraint worth re-evaluating, but local blast radius) becomedocs/decisions.mdnotes; routine bug fixes, obvious choices, and time-bound state are declined rather than padding either log. The human only confirms or overrides the proposed routing. - The diff shape of the appended entry matches the surrounding entries in the target file — the skill reads the file's existing format and matches it; it does not invent a new shape.
- Decision slugs are checked for uniqueness before append (
grep '^## decision-id: <slug>'); a collision surfaces the existing entry and asks (different slug / supersede / abort). - When a type-specific flow needs information the user didn't supply and can't infer (an area pick, a slug, a signal field), the skill elicits it — the bar is "genuinely ambiguous, multiple equally-valid choices," not "any uncertainty."
Failure modes to avoid.
- Adding friction prompts in place of audit-driven fixes. If mechanical captures consistently land wrong, the corrective loop is
/audit-skill log→ fix the SKILL.md → re-dogfood — NOT a confirmation prompt gating every invocation. Per-session friction is the worse pathology than a rare wrong capture. (Thedecisiontype's diff-and-confirm is not this anti-pattern — it gates a classification judgment, not a mechanical append.) - Decision-log creep + ADR creep. The significance bar is load-bearing at two levels: a routine fix, an obvious choice, or time-bound state is NOT a decision entry at all; and a decision that's local in blast radius is a
docs/decisions.mdnote, NOT a numbered ADR. If everything becomes an entry the high-signal ones drown; if every decision becomes an ADR, no decision is architectural. - Letting the human predict ADR-grade at capture time.
/log decisionmust NOT ask the user "is this an ADR?" up front — that re-imports the prediction-at-capture friction the agent-gate exists to remove. The agent classifies with full session context and routes; the human only confirms or overrides the proposed routing in one tap. - Inventing missing fields when they're not inferable. If the user said "log a followup" with no body or inferable area, ask — don't pick a plausible-looking placeholder. The bar is "genuinely ambiguous," not "any uncertainty."
- Misrouting a followup as a decision (or vice versa). A "remember to do X next session" is a
followup, not adecision; a "we chose X over Y because Z" is adecision, not a followup bullet. When the type token is absent and the body is genuinely ambiguous between the two, ask rather than guess — the two land in different files with different gates. - Routing to the wrong type on ambiguous input. When the first argument could plausibly be a type-name OR a body-word ("decision"... about what? — or is "decision" the body?), surface the ambiguity and ask. Don't optimize for the common case at the cost of the wrong-case audit corruption.
- Folding a closure into a
/logcapture. Don't strike-through, ✅-mark, or otherwise "close" an existing bullet during a/logrun, and don't touch a different bullet than the one you're writing. Closure is/done's job, as a separate invocation./log followup --replace=<substring>is not an exception to this: it REVISES one bullet the caller named explicitly and leaves it open under## Open followups, writing nothing to## Recently shipped. The rule guards against a/logrun silently touching a bullet nobody asked about — not against revising the one it was pointed at. - Bumping multiple journals when only one was meant. Each type's flow has a defined write surface; cross-bumping is a smell (the one sanctioned cross-write is the
last-updated:bump that keeps the staleness banner honest). - Manually bumping auto-maintained signal fields. The
latest_upstream+last_checkedfields for aggregator-managed slugs (jellyfin-server-stable,jellyfin-server-rc,roku-os) are owned byscripts/catchup-state.js; don't hand-edit them.
When NOT to use.
- The capture is actually a normal commit message body — just write the commit; don't pile a
/logon top. - The capture is a half-thought — write it down informally first, refine it, THEN
/logonce the shape is clear. Premature/logproduces noise the next/catchuphas to wade through. - The flip is a status change on an existing entry (open → closed, watching → re-checked) — that's
/done, not/log./logis for new entries. - You're deliberately writing a heavyweight ADR by hand (a big architectural decision with a long Context / Alternatives section).
/log decisionis the fast-capture path that drafts and routes for you, not a requirement: a hand-written ADR indocs/adr/(plus itsdocs/adr/README.mdindex row) is a normal commit. - The capture belongs to one tracked project (a phase note, not cross-cutting). It goes in that project's local PLAN: resume the project (
/resume-project) and record it there. - Internal tech debt (a deferred refactor, a design intent that shouldn't be casually reformed) →
/tech-debt-scanownsdocs/architecture/tech-debt.md. - A user-facing bug or feature request → file a GitHub issue (
gh issue createor/create-issue).
Implementation
The unified capture surface for JellyRock's project journals: decisions, progress followups, signals. The decision route supersedes the old /add-decision skill — it keeps that skill's discipline bar but moves classification to the agent (ADR-grade vs. sub-ADR note vs. decline) instead of a static human-read checklist.
Inputs
$ARGUMENTS: <type> <rest...> where <type> is one of decision, followup, signal, running.
If $ARGUMENTS is empty or <type> isn't recognized: list the four valid types with one-line descriptions and ask which one. Don't guess.
The capture rule
This skill is the ONLY sanctioned write path for docs/decisions.md, docs/progress.md, and docs/signals-backlog.md. Per the root AGENTS.md capture-discipline rule: agents do NOT use raw Write or Edit on those three files — captures flow through /log, closures through /done. Mechanical captures (followup, signal, running) apply directly — no per-invocation confirmation prompt; trust the skill, and fix systematic wrongness via /audit-skill log (a per-session diff-confirm is the wrong corrective loop, and git reset --soft HEAD~1 recovers a rare bad capture). The decision type is the exception — it surfaces a diff-and-confirm because the gate is confirming a significance + routing judgment, not a mechanical append. (A sub-agent invoking /log always surfaces and never auto-applies — its context dies at exit; see Sub-agent invocation.)
Step 1 — Route by type
Inspect the first whitespace-separated token of $ARGUMENTS:
decision→ Step 2-Dfollowup→ Step 2-Fsignal→ Step 2-Srunning→ Step 2-R
Anything else (including missing): tell the user the four valid types and ask.
One ambiguous input is asked about instead of routed: the first token is a type name but the rest reads as a sentence that starts with that word (running low on device-test time, decision on the lint rule is still open, signal handling in the socket task is flaky). Ask which type it is (or whether the whole input is the body of another type); anything else routes as above without asking.
Step 2-D — Decision (agent-gated)
The one flow where the agent does classification work, not mechanical routing. The user supplies content; the agent drafts, classifies, routes, and confirms. JellyRock keeps a two-tier decision surface: ADR-grade decisions are numbered, immutable records in docs/adr/; sub-architectural decisions are lightweight notes in docs/decisions.md. Supersedes the old /add-decision skill's static human-read checklist.
1. Draft
From the rest of $ARGUMENTS + full session context, draft the decision record: what was decided, why, what was considered and ruled out, any constraint or trade-off behind the choice.
2. Apply the significance gate
First, does it clear the decision bar at all? (Per docs/decisions.md's "When to add a note":)
- ✅ Has a non-obvious rationale not apparent from the code alone (e.g., "task pool children-as-vehicles dodge for SceneGraph event coalescing").
- ✅ Closes off alternatives someone might reasonably re-propose (e.g., "custom translation system, not Roku's
tr()"). - ✅ Has a constraint / trade-off worth re-evaluating later (e.g., "hardcoded
30sAPI timeout"). - ❌ Routine bug fix / obvious choice / time-bound state — the commit + code is enough; not a decision.
Then classify the blast radius — the negative filter ("if every decision is architectural, none is"):
- ADR-grade — architectural, hard-to-reverse, OR cross-component.
- Sub-architectural — clears the bar but is local (one component / file / tooling surface).
- Trivia — doesn't clear the bar at all.
3. Route on the verdict
- ADR-grade → draft a new numbered ADR at
docs/adr/NNNN-<slug>.md(next number in sequence;ls docs/adr/*.mdto find it) in JellyRock's house style:# ADR NNNN: <title>, then**Status:** Accepted/**Date:** <today>(usedate +%Y-%m-%d) / optional**related-files**:line, then 1-2 tight prose paragraphs (why; what was considered; what was ruled out; constraints). ALSO add the row to thedocs/adr/README.mdindex table. If it supersedes an existing ADR, write it as a new ADR that flips the older one's**Status:**toSupersededand adds a>pointer banner — the old record stays in place (ADRs are superseded, not edited). - Sub-architectural → append a slug-based note to
docs/decisions.mdusing the schema below. Insert after the last## decision-id:note's closing blank line — which may NOT be the file's last section: a trailing## Migrated to ADRstable sits at the end, so append after the last note, never after that table. The file is append-only for notes — never insert mid-file or rewrite older notes. - Trivia → decline in one line ("below the decision bar; not recorded"). Write nothing.
The sub-ADR note schema (docs/decisions.md):
## decision-id: <stable-kebab-case-slug>
**date**: YYYY-MM-DD
**status**: accepted | superseded | withdrawn
[optional, in this order, only when applicable:]
**supersedes**: <other-slug>
**superseded-by**: <other-slug>
**partially-supersedes**: <other-slug> (<what moved>)
**partially-superseded-by**: <other-slug> (<what moved>)
**related-files**: <comma-or-list of repo-relative paths>
[body: 1-2 short paragraphs. Why; what we considered; what we ruled out;
any constraints or trade-offs. If it grows long, it's probably an ADR.]
4. Slug uniqueness
The slug (≤5 words, kebab-case, stable — the cross-reference key in commits, PRs, and other entries) must be unique on its target surface:
- For an ADR: scan
ls docs/adr/for an existingNNNN-<slug>.md. - For a note:
grep -n '^## decision-id: <slug>$' docs/decisions.md.
If it collides, surface the existing record and ask: (a) pick a different slug, (b) supersede the old one (triggers the supersede-chain handling above), or (c) abort. If only a free-form description was passed, propose a slug and ask before locking it — slugs are stable references and renaming later is painful.
5. Diff-and-confirm, then apply
Surface the proposed routing (ADR / note / decline) plus the drafted content as a diff. The user confirms, or overrides the routing in one tap (promote a note to an ADR, demote an ADR to a note, redirect). No file is written before confirmation — this is the one /log path with a gate, and it gates the agent's judgment, not a mechanical append. Then apply the confirmed write via Edit (the note and/or the README index row) or by writing the new ADR file. For a sub-ADR note that uses **supersedes**, ALSO flip the older note's **status**: accepted → superseded and add **superseded-by**: <this-slug> below its status line — the older note stays in place. Note fields must land in the contiguous block directly under the heading; the linter stops reading at the first line of prose.
Before writing a full supersede, ask whether it's actually a PARTIAL one. If only part of the older note was replaced and the rest is still live, the full ritual would be a lie — use **partially-supersedes**: <old-slug> (<what moved>) on the new note and **partially-superseded-by**: <this-slug> (<what moved>) on the old one, and leave BOTH accepted. The scope annotation is required. This mirrors the ADR tier (0003/0004, 0008/0011), where the partially-superseded record keeps **Status:** Accepted. A note can be partially superseded by one record and later fully superseded by another.
withdrawn is terminal — the decision was abandoned, not replaced, so a withdrawn note has no successor: never supersede one, and never let a withdrawn note declare **supersedes**. If a note has grown ADR-grade, that's a promotion judgment (route it as an ADR), not a **superseded-by** pointer — every pointer must resolve to a slug in docs/decisions.md, and cross-tier references are prose markdown links instead.
5b. --revise=<slug> — the record is WRONG, not superseded
/log decision --revise=<slug> edits an existing docs/decisions.md note in place. It is the one exception to the append-only rule, and the distinction it turns on is load-bearing:
- Supersede — the decision CHANGED. The old record was true when it was written; it stays, and a new note points at it. This is the normal path.
- Revise — the record MISDESCRIBES what was decided or what shipped. No decision changed; the prose is simply wrong about reality. Superseding here would be a lie — it asserts a decision that never happened, and leaves the false statement as the first thing a reader hits.
Use --revise ONLY where the record does not match the code or the decision it claims to describe: a function name that no longer exists, a mechanism a later commit reverted, a measurement quoted wrong. Changing your mind is a supersede. Polishing wording is neither — leave it alone.
The flow is the same gate as an append: draft the corrected text, surface it as a diff against the current entry, confirm, then Edit in place. Do not touch **status** — a revised note stays accepted, because nothing about the decision's standing changed — and do not add a supersede pointer. Run npm run lint:docs after, exactly as for an append.
The common case is a record written earlier in the SAME unmerged branch, describing an approach a later commit on that branch replaced. Correcting it before the PR lands is finishing the entry, not rewriting project state.
6. Verify
npm run lint:docs
This validates: every tech-debt.md#anchor ref resolves, every relative markdown link in the touched record (docs/adr/*.md and docs/decisions.md) resolves, and — for docs/decisions.md notes — the supersede chain is consistent: unique slugs, one value per field, a valid status enum, every pointer resolving to a real slug in that file, both the full and the partial pair symmetric, a superseded note actually reading superseded and naming its successor, withdrawn staying terminal, and nothing pointing at itself. Exit 0 = clean.
ADR supersede chains are NOT machine-checked. ADRs express supersession as prose in a **Status:** line (Superseded by [ADR 0024](…), and the **Partially superseded by:** ADR 0011 (per-finding-default output only) variant), which has no field to validate. Get the ADR side right by hand.
Step 2-F — Followup
Appends a bullet to a ### <area> subsection of ## Open followups in docs/progress.md — or, with --replace=<substring>, revises one existing bullet in place — then bumps the file's last-updated: frontmatter to today.
Capture
Elicit (or derive from $ARGUMENTS):
- text: the followup description (one line, ~80 chars max). May be quoted in
$ARGUMENTS. - area: one of the recognized areas (
scripts,components,source,tests,docs,claude, etc. — match an existing### <area>subsection in progress.md, OR propose adding a new subsection). Append mode only —--replacekeeps the target bullet's existing area. --replace=<substring>(optional): revise ONE existing bullet in place instead of appending a new one. See below.
If --area=<name> is not in $ARGUMENTS, infer from the recent working context (last commit's touched files map to an area; an open editor file's path) or ask. Don't guess silently.
Compose the diff — append mode (the default)
- If the target area subsection contains a
(none)placeholder line, REMOVE that line and insert the new bullet- <text>in its place. - Otherwise, insert
- <text>as the last bullet under the area heading (preserving any existing bullets above). - ALSO update the frontmatter:
last-updated: YYYY-MM-DD→ today's ISO date. Usedate +%Y-%m-%dto get today.
If the target area doesn't exist as a subsection, propose adding ### <area>\n\n- <text> at the bottom of the ## Open followups section. Ask before applying.
Compose the diff — --replace=<substring> mode
Why this exists. A followup that lists ordered steps has no other way to record that ONE step shipped. /done prepends the matched bullet's text VERBATIM to Recently shipped, so closing a three-step entry because step 2 landed publishes a shipped-line claiming the whole thing — which /done's own "closure writes reflect reality, not optimism" rule forbids. Append-only /log leaves the stale bullet standing beside a new one that contradicts it, so /catchup reads whichever it hits first. The gap was filed as a followup in docs/progress.md after it was hit closing step 1 of the ODC-calibration entry, and hit again on step 2. This mode is the fix, and it keeps the write inside the skill — which is the property the capture-discipline rule actually cares about.
- Search the bullet TEXT of every
### <area>subsection under## Open followupsfor<substring>(plain substring, case-sensitive). - Exactly one match is required. On zero matches, refuse and say so — do not fall back to appending, because a silent append is precisely the two-contradicting-bullets state this mode exists to prevent. On more than one, refuse and print the matching bullets' opening words so the user can supply a longer substring; never pick one.
- Replace that bullet's text with
<text>. Keep it in its existing### <area>subsection and at its existing position — a revised entry is the same entry, and moving it would churn the ordering/catchupand/focusread. - ALSO bump
last-updated:to today, exactly as append mode does.
--replace revises; it never closes. The bullet stays under ## Open followups and nothing is written to ## Recently shipped. If the whole followup is done, that is /done, as a separate invocation. If the revision would leave the bullet saying nothing is outstanding, that is the tell that you wanted /done instead.
Surface, apply, verify
Shortened here. Read the whole file on GitHub.
Signals
- GitHub stars
- 45
- Forks
- 2
- Last commit
- Oct 2026
Advanced
- Item type
- skill
- Key
log- Source
- github.com/jellyrock/jellyrock
github.com/jellyrock/jellyrock
Related picks
Skill · larksuite
The pick for Markdownmarkdown-formatter
Skill · nvidia
The pick for Markdownhandoff
Skill · mattpocock
More in Docs & knowledgecanvas-design
Skill · anthropics
More in Docs & knowledgedoc-coauthoring
Skill · anthropics
More in Docs & knowledgepopups
Skill · coreyhaines31
More in Docs & knowledge