* docs/building.md — how to build jj-commitd and planctl from source, requirements, `go install` recipes, reproducible-build flags (`-trimpath -ldflags="-buildid="` per planctl PRD R7.3), test + benchmark commands, cross-compile, CI matrix link. * docs/planctl.md — full command reference beyond --help: plan-dir discovery cases A-D, all 9 classification codes with severity and meaning, tag-grammar spec (including paren-aware annotations + the tag-unclosed recovery semantics), the five EARS regexes and the bold-prefix exemption, JSON schema, worked examples for pre-commit / CI / multi-plan / JSON consumers. * docs/jj-commitd.md — architecture diagram, socket event protocol (session-start, post-edit, session-end, shutdown, status) with field tables, all env vars (REPO_ROOT, JJ_HOOK_DEBOUNCE_SEC, JJ_HOOK_STALE_MIN, JJ_HOOK_AUTO_SQUASH), baked-in timing constants, socket / log paths, fallback mode, troubleshooting. * README.md — expanded the jj-commitd bullets and linked to each reference from a new "Documentation" section; kept top-level summaries terse. |
||
|---|---|---|
| .claude | ||
| .forgejo/workflows | ||
| cmd | ||
| dev | ||
| docs | ||
| scripts | ||
| .gitignore | ||
| AGENTS.md | ||
| CLAUDE.md | ||
| go.mod | ||
| go.sum | ||
| INTEGRATION.md | ||
| README.md | ||
jj-template
Reusable jj + Claude Code workflow template. Provides automatic per-session snapshot management so every Claude Code session's work is committed and isolated — even with concurrent agents.
What It Does
- Session start: snapshots any pre-existing uncommitted work before the agent starts editing
- Post-edit: tracks every file Claude edits (via Edit/Write/NotebookEdit tools) per-session
- Session end: commits tracked files with a descriptive
wip(claude:<session>):message, then commits any untracked leftovers - Concurrent safety: multiple agent sessions on the same repo get isolated, file-scoped commits
- Bookmarks: each session's commit gets a
wip/claude-{session}bookmark for easy reference - Base tracking: records the starting revision per session (visible in
status) - Orphan reaping: dead sessions (crashed CLI) are cleaned up automatically via PID liveness checks and 30m timeout (configurable via
JJ_HOOK_STALE_MIN) - Legacy cleanup: daemon sweeps orphaned
/tmp/jj-claude-*-filesfrom pre-daemon hook versions on startup - Conflict detection: warns when multiple sessions edit the same file
- Squash:
squash-wipconsolidates accumulated wip commits into one for cleaner history - Auto-squash: set
JJ_HOOK_AUTO_SQUASH=1to squash automatically at session end - Repo cleanup:
/repo-cleanupClaude command organizes wip commits into themed conventional commits
Commit Daemon (jj-commitd)
A Go daemon that batches file edits into debounced commits via a Unix socket.
- How it works:
session-startlaunches the daemon;post-editsends file paths over a socket; a debounce timer (default 3s) batches edits into a singlejj commit;session-endflushes pending commits and shuts down. - Install:
go install forgejo.zerova.net/sid/template-jj/cmd/jj-commitd@latest. - Config:
JJ_HOOK_DEBOUNCE_SEC(default3, max30),JJ_HOOK_STALE_MIN(default30),JJ_HOOK_AUTO_SQUASH=1to squash at session end. - Session inventory: on
session-start, returns other active sessions and their tracked files. - Logging: daemon log at
/tmp/jj-commitd-<repo_id>.log. - Fallback: without the binary on
PATH, the hook falls back to file-tracking-only mode that commits at session end. - Full reference:
docs/jj-commitd.md.
planctl
Lint tool for spec-driven plan directories (dev/plans/<YYWWD>-<feature-slug>/). Validates traceability tags, cross-references between prd.md / design.md / tasks.md, file-presence at close-out, and EARS-keyword conformance on PRD acceptance criteria. Read-only by design — v1 ships planctl lint and nothing else.
- Install:
go install forgejo.zerova.net/sid/template-jj/cmd/planctl@latest. - Usage:
planctl lint [plan-dir]— pass a path, or invoke from anywhere inside a plan dir or a repo containingdev/plans/. - Output: one line per diagnostic in the form
<path>:<line>: [<severity>] <code>: <message>; a clean plan prints one summary line.--format=jsonemits JSONL for tooling. - Flags:
--strict(warnings → exit 1),--no-ears(skip EARS check),--format={text,json},--color={auto,always,never}(no-op in v1). - Classification codes:
tag-syntax,tag-unclosed,orphan-requirement,orphan-design,uncovered-requirement,uncovered-design,missing-prd,missing-closeout-file,ears-violation. These are grep-stable public API. - Full reference:
docs/planctl.md. - Spec:
dev/plans/26172-planctl/— PRD, design, task list, and codex-review log.
Documentation
docs/building.md— build both binaries from source, reproducible builds, cross-compile, CI matrix.docs/planctl.md— fullplanctlcommand reference.docs/jj-commitd.md— fulljj-commitddaemon reference.INTEGRATION.md— integrate this template into an existing or new project.AGENTS.md— cross-agent working conventions.
Prerequisites
- jj (Jujutsu VCS)
- jq (JSON processor)
- Claude Code CLI
- Go 1.22+ (optional, for building the commit daemon)
Quick Start
See INTEGRATION.md for step-by-step instructions to add this to an existing or new project.
Files
cmd/jj-commitd/
main.go # Commit daemon (Go)
scripts/
_lib.sh # Shared utilities (REPO_ROOT resolution)
jj-hook.sh # Main hook script (all 6 actions)
test-jj-hooks.sh # 26-test integration suite
.claude/
settings.json # Hook configuration for Claude Code (team-shared)
commands/
repo-cleanup.md # /repo-cleanup slash command
Manual Commands
# Check active sessions for this repo
./scripts/jj-hook.sh status
# Squash all wip commits between main and @ into one
./scripts/jj-hook.sh squash-wip
# Force-reap all non-alive sessions
./scripts/jj-hook.sh reap
How It Works
Tracking Files
Each active session gets a tracking file at /tmp/jj-claude-{REPO_ID}-{SESSION_ID}-files. The REPO_ID is a cksum of the repo root path, preventing cross-repo contamination. Companion files record the parent process (-pid) and starting revision (-base) for liveness checking and cleanup context.
Commit Flow
With daemon (default when jj-commitd binary is available):
session-start → snapshot pre-existing work
→ launch jj-commitd daemon (or connect to existing)
→ record base revision, reap stale sessions
post-edit (per file) → send file path to daemon via Unix socket
→ daemon resets debounce timer (3s default)
→ on timer expiry: commit all batched files
session-end → flush pending commits (daemon commits immediately)
→ set wip/claude-{session} bookmark
→ commit untracked leftovers (if sole session)
→ auto-squash (if JJ_HOOK_AUTO_SQUASH=1)
→ clean up tracking + PID + base files
Without daemon (fallback):
session-start → snapshot pre-existing work
→ record base revision, initialize tracking file
→ reap stale/orphaned sessions
post-edit (per file) → append relative path to tracking file (dedup)
session-end → commit tracked files (file-scoped)
→ set wip/claude-{session} bookmark
→ commit untracked leftovers (if sole session)
→ auto-squash (if JJ_HOOK_AUTO_SQUASH=1)
→ clean up tracking + PID + base files
Concurrency
When multiple Claude sessions edit the same repo simultaneously:
- Each session tracks its own files independently
- Session A ending only commits files A touched
- Untracked changes (Bash-created files) are only committed when the last session ends
- If both sessions touch the same file, the first to end commits it; the second skips it (no diff remaining)
Tests
scripts/test-jj-hooks.sh
Runs 34 integration tests in temporary jj repos. Requires jj and jq. Portable across macOS and Linux.