Scratch tool: logs session.append rows to /tmp/row-logger.json

<h1 align="center">claude-code-mod-tracking</h1>
__ __ ___ ___ _____ ___ _ ___ _ _____ _ _ ___
| \/ |/ _ \| \ |_ _| _ \ /_\ / __| |/ /_ _| \| |/ __|
| |\/| | (_) | |) | | | | / / _ \ (__| ' < | || .` | (_ |
|_| |_|\___/|___/ |_| |_|_\/_/ \_\___|_|\_\___|_|\_|\___|
#42 ──▶ PROJ-7 ──▶ https://… ──▶ [ tracking GitHub 4 (1 ✗) ]
<strong>Claude Code mods that keep track of the work around your session.</strong><br> Issues, PRs, Jira items, links, worktrees and agents — in one live pane.
<a href="https://github.com/martin-macak/claude-code-mod-tracking/actions/workflows/test.yml"><img alt="test" src="https://github.com/martin-macak/claude-code-mod-tracking/actions/workflows/test.yml/badge.svg?branch=main"></a> <a href="https://github.com/martin-macak/claude-code-mod-tracking/actions/workflows/lint.yml"><img alt="lint" src="https://github.com/martin-macak/claude-code-mod-tracking/actions/workflows/lint.yml/badge.svg?branch=main"></a> <a href="https://github.com/martin-macak/claude-code-mod-tracking/actions/workflows/release.yml"><img alt="release workflow" src="https://github.com/martin-macak/claude-code-mod-tracking/actions/workflows/release.yml/badge.svg"></a> <a href="https://github.com/martin-macak/claude-code-mod-tracking/releases/latest"><img alt="latest release" src="https://img.shields.io/github/v/release/martin-macak/claude-code-mod-tracking?display_name=release&sort=semver"></a> <a href="#requirements"><img alt="Claude Code 2.1.295 or newer" src="https://img.shields.io/badge/Claude%20Code-2.1.295%2B-D97757"></a> <a href="LICENSE"><img alt="MIT license" src="https://img.shields.io/badge/license-MIT-blue"></a> <a href="https://github.com/martin-macak/claude-code-mod-tracking/commits/main"><img alt="last commit" src="https://img.shields.io/github/last-commit/martin-macak/claude-code-mod-tracking"></a> <a href="https://github.com/martin-macak/claude-code-mod-tracking/issues"><img alt="open issues" src="https://img.shields.io/github/issues/martin-macak/claude-code-mod-tracking"></a> <a href="https://www.conventionalcommits.org/en/v1.0.0/"><img alt="Conventional Commits" src="https://img.shields.io/badge/Conventional%20Commits-1.0.0-fe5196"></a> <a href="#report-a-bug-or-ask-for-a-feature"><img alt="PRs welcome" src="https://img.shields.io/badge/PRs-welcome-brightgreen"></a>
<a href="#features">Features</a> · <a href="#installation">Installation</a> · <a href="#usage">Usage</a> · <a href="#report-a-bug-or-ask-for-a-feature">Report a bug</a> · <a href="#development">Development</a> · <a href="plugins/artifact-tracking/README.md">Full docs</a>
This repo holds Claude Code mods (function-hooks plugins) and the research behind them.
The first mod is artifact-tracking. A session mentions GitHub issues and PRs, Jira work items, Claude artifacts and web links. The mod finds them, fetches their live state and shows them in a /track pane and in a band above the prompt. You stop losing the PR from an hour ago in the scrollback.
[!NOTE] Mods are in early access. The API changes between Claude Code releases. This repo needs Claude Code 2.1.295 or newer.
![]()
You mention a PR, an issue and a docs link in a normal prompt. The mod finds them, and the band above the prompt counts them at once. A second prompt adds a PR with failing checks, and the band shows (1 ✗). /track opens a pane with the live title, state and checks of each item from gh, and a section for web links. Press r to refresh every item and Esc to close the pane.
The GIF comes from a Gherkin scenario, e2e/features/tracking.feature, that make demo records. The same scenario runs as a test under make e2e.
owner/repo#N, bare #N, Jira URLs and web links in your prompts and in Claude's replies, also from subagents. Tool output gives explicit GitHub and Jira URLs only.gh (one GraphQL call for each host) and acli.tracking Jira 6 · GitHub 4 (1 ✗) · Links 2 /track./track opens a pane with one section for each source. Press r to refresh, x to hide an auto row, Esc to close./clear, --resume and --continue.gh or acli, the items stay in the list and the section says why. A circuit breaker pauses a failing tool for 5 minutes.gh 2.102 or newer, logged in. It gives the live state of GitHub items.acli 1.3.19 or newer, logged in. It gives the live state of Jira items.In a Claude Code session:
/plugin install artifact-tracking --marketplace martin-macak/claude-code-mod-tracking
Answer y to add the marketplace mod-tracking, then pick a scope. From a shell:
claude plugin install artifact-tracking --marketplace martin-macak/claude-code-mod-tracking
Get a new release:
claude plugin update artifact-tracking@mod-tracking
Each GitHub release attaches artifact-tracking-<version>.zip, a SHA256SUMS file and a build provenance attestation. Load a zip for one session:
claude --plugin-url https://github.com/martin-macak/claude-code-mod-tracking/releases/download/artifact-tracking--v<version>/artifact-tracking-<version>.zip
git clone https://github.com/martin-macak/claude-code-mod-tracking.git
cd claude-code-mod-tracking
claude --plugin-dir plugins/artifact-tracking # one session
make install # every session, as a symlink
Work as usual. Mention issues, PRs, Jira keys and links in your prompts. The band fills by itself.
| Command | Action |
|---|---|
/track | Opens the pane and refreshes the items that are due. |
/track refresh | Refreshes every item and waits. Use it in claude -p. |
/track clear | Removes all items of this session. |
The mod README lists every captured pattern, the auto-tracking rules, persistence and the known limits.
This project is young, and your feedback shapes it. A short report helps a lot. Did something break? Is a pattern missing? Do you want a new column or a new mod? Tell us.
Search the open issues first, and add a 👍 to an issue that you also need. Pull requests are welcome too. See Contributing.
Requirements: claude 2.1.295 or newer, mise with node@24, and pre-commit. gh and acli are optional.
make init # check the tools
make hooks # install the git hooks (once per clone)
make test # validate, type-check and test the mod
make install # load the mod in every session
make e2e # run the Gherkin scenarios against a real claude (local only)
make demo # record docs/assets/demo.gif from the @demo scenario
make e2e and make demo also need tmux, asciinema, agg and gifsicle (brew install tmux asciinema agg gifsicle). They use the Claude login and trust store of the calling shell (CLAUDE_CONFIG_DIR, else ~/.claude), and they run real model turns. To refresh the GIF, follow the demo-scenario skill.
Run make help for every target.
| Path | Content |
|---|---|
plugins/ | The mods. One folder per mod. |
e2e/ | Gherkin scenarios that drive a real claude in tmux, the demo recorder and their tests. |
docs/knowledge-base/ | Research notes, one folder per problem. Start with claude-code-mods/. |
docs/superpowers/specs/ | Design specs. |
AGENTS.md | Rules for agents and contributors: lint, branches, commits, PRs, issues. |
Makefile | Build, test, lint and install targets. |
make lint runs all hooks in .pre-commit-config.yaml on all files.
| Hook | Checks |
|---|---|
pre-commit-hooks | Whitespace, end of file, line endings, YAML, JSON, merge markers, symlinks, large files, private keys, no commit to main. |
markdownlint-cli2 | Markdown. Config: .markdownlint-cli2.jsonc. |
biome-check | Format, lint and import order of plugins/ and e2e/. Config: biome.json. |
shellcheck | Shell scripts. |
actionlint | GitHub Actions workflows. |
typecheck | tsc on the mod and on e2e/ (make typecheck). |
conventional-pre-commit, commit-subject-case | Commit messages. See AGENTS.md. |
| Workflow | Runs |
|---|---|
test | make test and make e2e-unit on every PR and push to main. |
lint | The pre-commit hooks, the PR title check and the branch name check. |
release | On a tag <plugin>--v<version>: validates, tests, builds the zip and publishes the GitHub release. |
claude, claude-code-review | Claude answers @claude mentions and reviews pull requests. |
Release steps: plugins/artifact-tracking/README.md.
Read AGENTS.md first. In short: branch <type>/<summary>, Conventional Commits with a sentence-case subject, one PR per change with Closes #N, squash merge. Run make verify before you push.
MIT © Martin Macak
hooks/register.ts 38 lines1// Observes every row `session.append` hands over and writes them to /tmp/row-logger.json.
2// A scratch tool for the live checks in this folder, not a mod to keep. Attachments are logged by name only.
3import type { EngineInterface, Register } from 'claude-code'
4
5const LOG = '/tmp/row-logger.json'
6
7const rows: unknown[] = []
8
9async function save($: EngineInterface): Promise<void> {
10 await $.fs.write(LOG, JSON.stringify(rows, null, 1))
11}
12
13export const register: Register = (on) => {
14 on('session.append', async ($, e, next) => {
15 const stored = await next(e)
16 const body = e.door === 'attachment' ? '(omitted)' : e.message.content
17 rows.push({ door: e.door, origin: e.origin, agentId: e.agentId, uuid: e.uuid, type: e.message.type, name: e.message.name, role: e.message.role, isMeta: e.message.isMeta, content: body })
18 await save($)
19 return stored
20 })
21 on('turn.complete', async ($, e, next) => {
22 rows.push({ turnComplete: { answer: e.answer, reason: e.reason, agentId: e.agentId } })
23 await save($)
24 return next(e)
25 })
26 on('session.start', async ($, e, next) => {
27 const messages = await $.session.messages()
28 rows.push({ sessionStart: { surface: e.surface, isInteractive: e.isInteractive, loaded: messages.length, messages: messages.map((m) => ({ role: m.role, text: m.text.slice(0, 160), toolUses: m.toolUses.length, toolResults: m.toolResults?.length })) } })
29 await save($)
30 return next(e)
31 })
32 on('classic.SessionStart', async ($, e, next) => {
33 rows.push({ classicSessionStart: { source: e.source } }) // never logged on this machine: sec-default bypasses user-tier hooks of this event
34 await save($)
35 return next(e)
36 })
37}
38