SLOPSHOPPER

phylax

Opt-in Claude Code hooks: refuse attribution lines in commits and PRs, refuse staging COMMITS.md, warn on commits in a main checkout, and restart idle sessions…

newguardprocess
★ 1v?MITupdated 2026-10-09ajbarea/techne/plugins/phylax
A shopper browsing a rack in a slop shop
README

<img src="docs/assets/hero.png" width="420" alt="techne Hero Image">

techne

A Claude Code plugin marketplace: skills for code repos and for documents, opt-in git guards, and a spoken Claude Code.

Validate Docs Python uv Claude Code License: MIT


Plugins

PluginForRuns in
techneWork in a code repo: audits, CI review, pre-merge review, commit plans, GitHub catch-up, cross-repo drift, slop and doc driftClaude Code
grapheDocuments: LaTeX papers, markdown-to-PDF, talk decks, paper scaffolds and novelty reviewClaude Code
dokimasiaBibliography verification for LaTeX projects: lint a .bib or hand-written reference list, verify it against arXiv and Crossref, check every cited key renderedClaude Code, or one standalone Python file
phylaxOpt-in git and PR guards (a mod), restart onto an updated Claude CodeClaude Code
keryxSpeaks a short gist of each reply in a local voice (WSL2)Claude Code

Install only the ones you use: every enabled plugin's skill list sits in Claude's context on every turn. graphe holds skills only, so claude.ai and Cowork can install it too, but its build and check steps run shell commands (uv, TeX Live, Typst) that need Claude Code.

techne

SkillWhat it does
techne:auditRuns the repo's make targets in dependency order and reconciles terminal output against logs/dev-*.log archives.
techne:auto-commitGroups working-tree changes into a structured COMMITS.md plan for staged review before anything lands.
techne:catchupReads every comment, review, and state change on a repo's issues and PRs since you last participated, then reports who is blocked on whom.
techne:ci-auditAudits GitHub Actions runs on the current branch/PR: surfaces warnings, failures, and noise; fixes what's fixable in-repo.
techne:deslopScans comments and docstrings for AI-generated slop and proposes tightened rewrites.
techne:docs-siteMaintains the Zensical-powered docs site: config, deploy pipeline, theming, link integrity.
techne:docsyncVerifies documentation claims (CLI commands, paths, config keys, signatures) against the actual code.
techne:elenchusAdversarial pre-merge review: drives /code-review, then reproduces the load-bearing claim, traces every consumer across the whole repo, and walks a bug-class rubric for reachable destructive ops, unmirrored parallel-path guards, migration crashes, and dead-but-green features.
techne:research-groundedFlags design decisions in IMPL/ROADMAP that lack # research(YYYY-MM): provenance, then web-searches to ground them.
techne:reslopRewrites docstrings grounded in the implementation rather than deleting them outright.
techne:sistersCross-repo drift audit across the sister repos listed in ~/.claude/techne.toml.
techne:theorosStarts an observed live dev session: Claude drives the REPL in a named tmux session; you spectate read-only via tmux attach -r.

graphe

SkillWhat it does
graphe:latexBuilds a LaTeX document and gates it on its log, its PDF, and the assignment it answers; a clean latexmk exit is not the signal.
graphe:paperScaffolds a new paper dir (LaTeX + results-harvest + shared bib + portfolio row) in a papers-style monorepo so it builds on day one.
graphe:paper-reviewPre-submission novelty + reviewer pass for a draft paper: grounds every novelty/claim verdict in retrieved prior work, flags related-work gaps, and surfaces lab-overlap for disclosure.
graphe:pdfRenders markdown to print-quality PDFs through a Typst template, then verifies fonts and content against the source.
graphe:slidesGates a talk deck before it is presented: real slide titles, contrast, alt text, stray figures; renders it through the app that will show it.

dokimasia

SkillWhat it does
dokimasia:checkLints any .bib or hand-written thebibliography offline, resolves its arXiv ids and DOIs against arXiv and Crossref and tells a failed lookup from a wrong entry, and checks that every cited key rendered in the built document. Configured per project, standard library only.

phylax

Three opt-in guards on git commit, git add and gh pr, run by a mod (Claude Code 2.1.287 or later): block attribution lines, from the text Claude Code composes through to the command Claude runs; block staging COMMITS.md; and warn on commits in the main checkout. While a blocking guard is on, a check that fails refuses the command instead of letting it through. A fourth option, restart_on_update, moves an idle session onto an updated Claude Code in a new tmux window or Windows Terminal tab and keeps the conversation. Each is off until you switch it on in /config. See Configuration and Restart on update.

Install

From inside Claude Code:

/plugin marketplace add ajbarea/techne
/plugin install techne@techne
/plugin install graphe@techne
/plugin install dokimasia@techne
/plugin install phylax@techne
/plugin install keryx@techne    # WSL2 on Windows only

Invoke a skill as /techne:<name>, /graphe:<name> or /dokimasia:check, or describe the task and Claude picks the matching skill. Run /skills to confirm they loaded. On claude.ai, add ajbarea/techne under Customize > Plugins > Add > Add marketplace, then add graphe.

First-time setup: the techne skills are opinionated about a few conventions (Makefile pattern, dev-runner archive, .claude/skill-context.md). See Conventions for the minimum each skill needs.

Configuration

techne:sisters reads ~/.claude/techne.toml at runtime (user-controlled config that lists the active sister repos to compare against).

github_user   = "your-github-username"
workspace_root = "/path/to/your/workspace"

[[sisters]]
name   = "repo-one"
status = "active"

[[sisters]]
name   = "repo-two"
status = "active"

[[sisters]]
name   = "repo-three"
status = "active"

Set status = "backburner" to skip a repo without removing it.

How it fits together

~/.claude/techne.toml      ← user-controlled sister-repo registry
        │
        ▼
techne (marketplace: ajbarea/techne)
├── techne (plugin, plugins/techne)
│   ├── audit             ── verifies build targets vs. logs/
│   ├── auto-commit       ── groups diffs into COMMITS.md
│   ├── catchup           ── who is blocked on whom since you last looked
│   ├── ci-audit          ── reads gh runs, fixes warnings in-repo
│   ├── deslop            ── flags AI-slop prose
│   ├── docs-site         ── manages Zensical site + deploy
│   ├── docsync           ── doc claims ↔ implementation
│   ├── elenchus          ── adversarial pre-merge review (reproduce + trace + rubric)
│   ├── research-grounded ── flags un-grounded design decisions
│   ├── reslop            ── rewrites docstrings from code
│   ├── sisters           ── cross-repo drift across sisters
│   └── theoros           ── observed tmux REPL session
├── graphe (plugin, plugins/graphe)
│   ├── latex             ── builds LaTeX and gates the PDF on its log
│   ├── paper             ── scaffolds a new paper dir (LaTeX + harvest)
│   ├── paper-review      ── grounded novelty + reviewer pass for a draft
│   ├── pdf               ── markdown to print PDF via Typst, verified
│   └── slides            ── talk deck gated and rendered, presenter briefed
├── dokimasia (plugin, plugins/dokimasia)
│   └── check             ── lints, verifies and render-checks a .bib
├── phylax (plugin, plugins/phylax) ── opt-in git guards + restart on update
└── keryx (plugin, ajbarea/keryx)    ── spoken gist of each reply

Each skill is self-contained. Invoke one without pulling in the others. They share a convention of writing intermediate artifacts (plans, audit reports) to disk for human review before mutating the repo.

Why "techne"

Greek τέχνη: craft, the practical knowledge of how to make a thing well. The plugins keep the Greek: γραφή (graphe) is writing, φύλαξ (phylax) a guard, κῆρυξ (keryx) a herald, δοκιμασία (dokimasia) the scrutiny of a candidate's credentials before office.

License

MIT.


<img src="docs/assets/brand.png" alt="" height="16" />

Source 1 files
hooks/register.ts 78 lines
1import type { PluginOptions, Register } from 'claude-code'
2
3// The guard options, as the manifest's userConfig names them.
4const GUARDS = ['block_attribution_trailers', 'block_commits_md', 'warn_main_checkout_commit'] as const
5// The guards that refuse a command; warn_main_checkout_commit only warns.
6const BLOCKING = ['block_attribution_trailers', 'block_commits_md'] as const
7// git_guards.py looks no further at a command without one of these words.
8const GIT_OR_GH = /\b(git|gh)\b/
9// A commit makes at most six git calls of 5 s each inside git_guards.py.
10const GUARD_TIMEOUT_MS = 40_000
11
12type Verdict = { deny?: string; warning?: string }
13
14const isOn = (options: PluginOptions, key: string): boolean => options[key] === true
15
16// Reads git_guards.py's PreToolUse JSON: a deny reason, or a warning for the model.
17export function readVerdict(stdout: string): Verdict {
18  if (stdout.trim() === '') return {}
19  const out = JSON.parse(stdout) as {
20    hookSpecificOutput?: { permissionDecision?: string; permissionDecisionReason?: string; additionalContext?: string }
21  }
22  const spec = out.hookSpecificOutput ?? {}
23  if (spec.permissionDecision === 'deny') return { deny: spec.permissionDecisionReason ?? 'phylax refused this command.' }
24  if (spec.additionalContext) return { warning: spec.additionalContext }
25  return {}
26}
27
28export const register: Register = (on, options) => {
29  // Claude Code reads the commit trailer and PR footer from here, so blanking them stops the
30  // lines before Claude writes them; the Bash guard below still catches one written by hand.
31  if (isOn(options, 'block_attribution_trailers')) {
32    on('attribution.text', { kind: ['commit', 'pr'] }, () => ({ text: '' }))
33  }
34
35  if (!GUARDS.some(key => isOn(options, key))) return
36  const blocking = BLOCKING.some(key => isOn(options, key))
37  const failed = (why: string) => ({
38    deny:
39      `phylax: the git guard ${why}, so this command was not run. Retry it in a simpler form, ` +
40      'or switch the guard off in /config.',
41  })
42
43  on('tool.call', { tool: 'Bash' }, async ($, e, next) => {
44    // A subagent's call goes to the hooks.json PreToolUse fallback, which gets its own cwd;
45    // $.session.cwd() is the main thread's.
46    if (e.agentId !== undefined || !GIT_OR_GH.test(e.command)) return next(e)
47    const cwd = await $.session.cwd()
48    const run = await $.process.run(['python3', `${$.plugin.root}/hooks/git_guards.py`], {
49      cwd,
50      stdin: JSON.stringify({ hook_event_name: 'PreToolUse', tool_name: 'Bash', tool_input: { command: e.command }, cwd }),
51      env: Object.fromEntries(GUARDS.map(key => [`CLAUDE_PLUGIN_OPTION_${key.toUpperCase()}`, String(isOn(options, key))])),
52      timeoutMs: GUARD_TIMEOUT_MS,
53    })
54    const verdict = readVerdict(run.stdout)
55    if (verdict.deny !== undefined) return { deny: verdict.deny }
56    if (run.exitCode !== 0) {
57      const reason = run.stderr.trim().split('\n')[0] || `exit ${run.exitCode}`
58      if (blocking) return failed(`failed (${reason})`)
59      $.ui.log(`phylax: the git guard failed (${reason}); the command ran unchecked.`)
60    }
61    // The hooks.json fallback runs inside next(e). Naming this call there makes it stand down
62    // for this call alone: any call this hook did not pass, it still checks.
63    if (e.tool_use_id !== undefined) await $.env.set('PHYLAX_GUARD_CHECKED', e.tool_use_id)
64    let result
65    try {
66      result = await next(e)
67    } finally {
68      await $.env.set('PHYLAX_GUARD_CHECKED', undefined)
69    }
70    if (verdict.warning === undefined || result.deny !== undefined) return result
71    $.ui.log(verdict.warning)
72    return { ...result, context: [...(result.context ?? []), verdict.warning] }
73  }).catch(($, e, next) => {
74    if (next.called || !blocking) return next(e)
75    return failed(`failed (${next.error.message})`)
76  })
77}
78