Conversation
Decouples scaffolded user content from the devtronic `thoughts/` convention (reserved for internal dev notes/plans/design). The scaffolded directory is now top-level `scribetronic/` under the user's project root. BREAKING CHANGE: existing v0.1.0 installs must run: mv thoughts/writing scribetronic rmdir thoughts 2>/dev/null - Move templates/project/thoughts/writing/ -> templates/project/scribetronic/ - Update all path strings in skills (agenda, write, write-publish, style-extract) - Update analyzer: ProjectAnalysis.hasWritingDir -> hasScribetronicDir - Update tests, docs, README, ARCHITECTURE, tutorials, CHANGELOG
Adds 20 new tests across four files; raises CLI test count from 27 to 47. - project.test.ts (new) — direct unit tests for analyzeProject covering empty dir, partial installs, all three orchestrator names, and a non-orchestrator skill correctly NOT triggering hasScribetronic - info.test.ts (new) — not-found exits 1, frontmatter+body printing, unknown frontmatter keys surfaced, list-valued fields, minimal skill - list.test.ts (new) — empty registry hint, category grouping, 80-char truncation, "(no description)" fallback, array-description joining - init.test.ts — adds: missing target path exits 1, missing templates warns and returns, idempotent re-run on an existing install - style.test.ts — adds: missing bundled seed exits 1
Closes the loop between drafted and published copy. The skill diffs (draft, published) pairs from the user's editorial history and proposes concrete deltas to writing-style/SKILL.md. Hard rule: no delta without ≥2 supporting pairs shown side-by-side. Never auto-rewrites the guide — output goes to scribetronic/style/refinements/<date>.md for manual review and merge. - New skill at templates/.../skills/style-refine/SKILL.md (5-phase workflow: inventory → diff → classify → synthesize → output) - writing-style/SKILL.md gains a "Refining this guide" footer pointing at the new skill - agenda + write-publish print a one-line nudge after 3+ pieces published since the last applied refinement - docs/skills.md updated (counts 21→22, Shared 4→5, new entry, quick lookup row) - CHANGELOG [Unreleased]/Added entry - bundled-skills.test.ts verifies the skill is shipped and registered under the Shared category via the real templates dir No CLI command added — auto-discovered by the existing skill registry.
- Add .github/workflows/ci.yml: typecheck, lint, test, build, pack-dry-run on Node 18/20/22 for push and PR. - Add .github/workflows/release.yml: tag v*.*.* triggers npm publish with provenance attestation; verifies tag matches package.json version; auto-creates GitHub release. - Add prepublishOnly script and publishConfig (access: public, provenance: true) so any publish runs the full quality gate. - Bump version to 0.1.1 — first npm-published release; promote 0.1.1 in CHANGELOG with style-refine + scribetronic/ rename, leave [Unreleased] holding the publish-infra changes for the next cut. - Add docs/releasing.md maintainer runbook (pre-flight, tag, post-publish, rollback, failure modes). - Update README install path to npm i -g scribetronic; rework Roadmap (v0.1 = published, v1.0 = stability). - Add planning doc under thoughts/plans/. Verified locally: typecheck + lint + 49 tests + build all green; tarball install in /tmp scaffolds 44 files including 21 skills and full scribetronic/ tree.
BREAKING CHANGE: `scribetronic init` no longer copies SKILL.md files into the project. Skills load at runtime from r-bart/scribetronic-plugin as /scribetronic:<name>. Existing v0.1.x installs: run `scribetronic update` then delete the duplicated .claude/skills/ entries — see CHANGELOG for the exact list. CLI changes - New commands: update, doctor, uninstall - init now writes .claude/settings.json registering the marketplace (preserves pre-existing keys) - Bump version to 0.2.0 - Add @vitest/coverage-v8 + npm run test:coverage script New modules - src/data/plugin.ts — marketplace constants - src/utils/settings.ts — settings.json read/write + register/unregister - src/commands/update.ts — refresh registration - src/commands/doctor.ts — 6-check health verification - src/commands/uninstall.ts — disable plugin (preserves user content) - src/generators/templateCopier.ts — adds exclude option Tests - 29 new tests across settings/doctor/update/uninstall - init.test.ts updated: no longer asserts skill copy, asserts settings write - Total: 78 tests / 12 files (was 49 / 8). Coverage 92.7% statements. Docs - New docs/plugin-mode.md (architecture, hooks, migration) - README quick-start: 3 install options (CLI / plugin direct / global) - cli-reference.md: documents update/doctor/uninstall, removes 'out of scope' section - CHANGELOG: 0.2.0 entry with breaking change + migration recipe - ARCHITECTURE: notes templates/claude-code/.claude/skills/ is now source-of-truth, not copied - 5 short-form skill descriptions: added 'Use when…' clauses for the router (M4 from audit) - CLAUDE.md / AGENTS.md / philosophy.md: skill count + architecture sync Tooling - scripts/sync-plugin-repo.sh — mirrors bundled skills to the plugin repo and bumps plugin.json:version on release
…style (v0.2.1) BREAKING (content): every long-form-*, short-form-*, editing-pass, and ai-slop-check SKILL.md is now format-only. Author names (Welsh, Koe, Moretti, Röhl), personal references (Roberto, MakerOps, MW#N), and "X-style" labels have been removed. Voice and references live exclusively in writing-style/SKILL.md, which ships as a fillable template. v0.2.0 was live for hours with no users, so practical migration impact is zero. Fixes - All 22 skills now load correctly in Claude Code. Previously 18 of 22 had non-spec frontmatter keys (inherits, formats, cadence, length_target, applies_to, input, format, quota, status, language, target_voice, sources, last_updated) that the skills loader silently rejects. Only 4 skills were registering as slash commands. Frontmatter now contains only the spec-allowed keys (name, description); operational metadata moved to a `## Metadata` body section. Changes - writing-style/SKILL.md rewritten as a personalization template: new section 0 "Reference sources" where the user lists their own authors/posts; <your-name> placeholders throughout; "How to fill this file" instructions; generalized native-language interference watch (was Spanish-specific). - 18 SKILL.md files normalized: frontmatter spec-compliant, body adds "Voice and tone come from writing-style/SKILL.md" pointer, generic example shapes labeled as such replace named-author quotes. - editing-pass + short-form-voice-adjustments: "Welsh-style punctuation paragraph" → "staccato 2-3 word paragraph" (format description, no author attached). - ai-slop-check: "tightened to Roberto's voice" → reads writing-style.md for user-specific tics. Tooling - scripts/normalize-skill-frontmatter.mjs — extracts non-spec keys from any SKILL.md frontmatter and migrates them to a `## Metadata` body section. Idempotent. Run after editing or adding skills. - .claude/rules/skills.md — new in-repo rule file documenting the two hard constraints (frontmatter spec compliance, format ↔ style decoupling) with grep checks for pre-commit verification. Bump CLI 0.2.0 → 0.2.1, plugin lockstep 0.2.0 → 0.2.1. Tests: 78/78 pass. Coverage 92.7% statements.
…ls rule
The previous commit's CLAUDE.md and .claude/rules/skills.md sections on
"format ↔ style decoupling" listed specific names as illustrative examples
of what NOT to embed — which itself violated the rule (the docs embedded
the names they forbade).
Changes:
- CLAUDE.md: forbidden-list rewritten in fully generic terms
("specific author or creator names", "the maintainer's own personal
identifiers", "<author>-style" placeholders).
- .claude/rules/skills.md: same generalization. The grep regression scan
now reads its name list from a separate .skills-regression-names file,
marked as an append-only detective ledger — explicitly NOT a
prescriptive whitelist of "the only forbidden names". Any name-shaped
reference is forbidden; the ledger only catches reintroductions of
patterns already removed.
- New .claude/rules/.skills-regression-names: hidden file, single-line
regex of historically-removed names. Maintainers append to it when
catching new contamination during code review.
Skills themselves remain clean (verified by the regression scan).
The .skills-regression-names file kept the very names we were trying to remove from the repo (Welsh, Koe, Moretti, Röhl, Roberto, MakerOps, MW#, sociilabs) checked into git just to power a grep. That defeats the purpose — those names are now visible to every contributor, indexed by GitHub search, and pushed to a public mirror. Trade-off: lose the automated regression net. Gain: the repo is fully clean of those references. The skills.md rule file now describes detection as "manual review by the reviewer" with a coarse heuristic (two-capitalized-words, @-handles, "Name-style"/"Name's" possessives) for opt-in use. False positives expected — use as a starting point, not a gate. CLAUDE.md updated to match.
… idea backlogs
Scan caught three leftover hits outside the SKILL.md files (which were
already clean):
- packages/cli/templates/claude-code/.claude/skills/README.md:
"Roberto's voice base" → "User's voice base, shipped as a personalization template"
Also added the missing style-refine entry, fixed 21 → 22 skill count.
- packages/cli/templates/project/scribetronic/README.md:
"Koe-style" / "Moretti-style" labels → format descriptions only.
- packages/cli/templates/project/scribetronic/ideas/{how-to,hot-take}.md:
same name-strip in the description frontmatter.
The plugin repo gets re-synced to pick up nothing new in skills/ but
correctness is verified end-to-end.
The previous v0.2.x code wrote the user's voice override to .claude/skills/writing-style/SKILL.md, which was orphan: skills loaded from the plugin marketplace cache, never from that path. User edits had no effect on drafts. Path migration - scribetronic style → writes to scribetronic/style/writing-style.md (project root, alongside calendar/, ideas/, publish-config.yaml) - doctor → checks the new path - init → scaffolds scribetronic/style/README.md with seeding instructions - bundled writing-style/SKILL.md template → header documents the override mechanism and resolution order - write, editing-pass, ai-slop-check, short-form-voice-adjustments → added "Voice resolution" section with explicit precedence: 1. scribetronic/style/writing-style.md (project) — wins if present 2. writing-style/SKILL.md (bundled template) — fallback - style-refine → reads/writes the new path - style-extract → already used the right path; no change Project scaffold - new templates/project/scribetronic/style/README.md with usage: scribetronic style | --reset | /scribetronic:style-extract | /scribetronic:style-refine Tests - style.test.ts and doctor.test.ts updated to assert new paths - 78/78 still pass - e2e smoke verified end-to-end: init creates style/, scribetronic style populates writing-style.md there, doctor reports 6/6 pass Docs - CHANGELOG entry under [0.2.1] documenting the path migration - docs/cli-reference.md style command paths updated - docs/plugin-mode.md gains a "Voice override" section explaining the override mechanism and resolution order Migration: v0.2.0 was live for hours with no users. If you already ran scribetronic style on v0.2.0 and edited the old path, copy that content to the new location and delete the old file.
…y UX Phase 1/5 of the v0.2.1 agent-friendly CLI plan. - utils/output.ts: shared router. data() goes to stdout (JSON-serialized in JSON mode, pre-formatted string in human mode). note/success/warn/ error all go to stderr in human mode. In JSON mode: data() emits one JSON line; note/success/warn are silenced; error() emits a structured envelope on stdout (gh/kubectl convention). NO_COLOR and TTY detection honored — chalk level is forced to 0 when piped or NO_COLOR is set. - utils/exit.ts: ExitCode constants — Success(0), Unexpected(1), Usage(2), State(3). Used to give agents a stable contract distinguishing bad-args from config-drift from internal-bug. No commands wired yet; that lands in Phase 2/3/4. Quality: typecheck + lint pass.
…exit codes Plan: thoughts/plans/2026-05-04_v0.2.1-agent-friendly-cli.md Implements all 5 phases of the post-publish CLI audit (Tier 1 + 2 fixes from the "Designing CLI for Agents" article). What changed - Read-only commands (list, info, doctor) accept --json and emit one newline-terminated JSON line on stdout. All chrome (progress, hints, decoration) is suppressed in JSON mode. - All commands route chrome to stderr; stdout is reserved for data. scribetronic init >/dev/null is silent on success but errors still reach stderr. - NO_COLOR=1 and non-TTY stdout disable color and clack chrome globally. - Granular exit codes: 0 success, 1 unexpected, 2 usage error (bad args/path, unknown skill), 3 state error (plugin not registered, doctor checks failed). Documented in --help epilog. - scribetronic style --reset accepts --yes (or SCRIBETRONIC_YES=1) to bypass the confirm prompt. Required for non-interactive shells. - scribetronic style (existing target, non-TTY) prints the path on stdout so an agent can capture it: path=$(scribetronic style) - --help epilog lists agent-canonical examples + exit code table + JSON output contract. How - New utils/output.ts: shared router enforcing the stdout/stderr contract. data() → stdout (JSON or pre-formatted string). note/success/warn/error → stderr (or suppressed in JSON; error envelope on stdout in JSON). Honors NO_COLOR and TTY detection automatically. - New utils/exit.ts: ExitCode constants for the contract above. - index.ts wires --json per command, configures output before each action, installs the help epilog, and re-routes the top-level catch. - 7 commands refactored to use out.* exclusively (no more raw console.log/error in command bodies). Tests - 78 → 106 tests across 14 files (28 new). - New helpers/captureStreams.ts: deterministic stream-capture helper used by every command test (replaces console.log spies). - New output.test.ts: 11 unit tests covering JSON mode, human mode, TTY/NO_COLOR detection, error envelope shape. - New json-mode.test.ts: 7 spawn-based E2E tests asserting actual stdout/stderr/exit-code from the built binary with NO_COLOR=1. - All existing command tests migrated from console.log → captureStreams. - Coverage: 91.26% statements, 78.74% branches, 95.74% functions (target was ≥90% statements per plan's done criteria). Docs - CHANGELOG [0.2.1]: new "Agent-friendly CLI" subsection. - docs/cli-reference.md: new "Agent-friendly modes" section at the end with --json schemas, global exit-code contract, environment variables, stdout/stderr discipline table, and 6 agent-canonical examples. Per-command exit code tables updated to match the new contract. Local-only, no push, no tag.
…ttings
Addresses the two minor warnings from the v0.2.1 post-review audit.
M1 — out.line() helper for stderr rendering loops
- New utils/output.ts:line(msg) writes to stderr, suppressed in JSON
mode, prints in non-TTY (unlike out.note which is silent there).
No prefix, no color logic — caller controls chalk styling.
- list.ts, info.ts, doctor.ts: replaced 30 raw process.stderr.write
calls with out.line. Now every stderr write in commands/ goes
through the output module, so future config knobs (NO_COLOR rules,
log levels, JSON envelope changes) apply uniformly.
M2 — utils/settings.ts migrated to node:fs/promises
- Was using readFileSync/writeFileSync/existsSync/mkdirSync, which
CLAUDE.md explicitly forbids in hot paths. Settings.ts is called by
all four mutation/inspection commands.
- All 5 exports now async: readClaudeSettings, writeClaudeSettings,
registerGitHubPlugin, unregisterPlugin, isPluginRegistered.
- Cascaded await to call sites in commands/{init,update,uninstall,doctor}.ts
and tests/{settings,update,uninstall,doctor}.test.ts.
- Try/catch on read collapses both ENOENT and JSON parse errors
to {} — same behaviour as before, but no more existsSync race.
Tests: 106/106 still pass. Quality gates clean.
E2E smoke: init+doctor+list --json all work end-to-end.
Local-only. No push.
… review New shared skill at packages/cli/templates/claude-code/.claude/skills/review/. Bundle count 22 → 23. What it does - Single-message dispatch of N Task subagents, one per focus. Default focuses: voice, structure, slop, hook, closer. Opt-in: factual (with --with-evidence; reads notes.md as ground truth). - Each subagent receives the resolved writing-style override + a focus- specific brief + the draft body, and returns a markdown findings table with severity (HIGH/MEDIUM/LOW), location (line/section), and the specific issue. - Orchestrator merges all tables into one severity-grouped report on stdout. Per-focus dispatch progress on stderr (silenced with --quiet). - Verdict line: SHIP (0 HIGH, ≤2 MEDIUM) or REVISE. - Models: haiku for pattern-matching focuses; bumps to sonnet when factual is enabled. Why - Wall-time ~10s for 5 parallel subagents vs ~50s sequential editing-pass + ai-slop-check, with strictly more coverage (structure, hook, closer, factual all new). - Designed for mid-draft iteration: pause every ~200 words, get feedback, keep writing. - From v0.3.0 onward, /write Phase 4 will call /review by default (opt-out via --no-review for legacy sequential flow). Bundle changes - +packages/cli/templates/claude-code/.claude/skills/review/SKILL.md - Skill count: 22 → 23 across CLAUDE.md, README.md, docs/skills.md, docs/plugin-mode.md, docs/philosophy.md, docs/cli-reference.md, templates/claude-code/.claude/skills/README.md. - Shared utilities count: 5 → 6 (writing-style, editing-pass, ai-slop-check, style-extract, style-refine, review). - README.md "Shared utilities (5)" → "(6)" + added /review row. - docs/skills.md "Shared (5)" → "(6)" + added /review section. - skills/README.md added review entry. Plugin repo synced (23 SKILL.md mirrored). plugin.json:version stays 0.2.1 — this skill ships as part of the next minor (0.3.0). No package version bump in this commit; entry under CHANGELOG [Unreleased]. Tests: 106/106 still pass (skill is markdown, no TS to test). E2E smoke: scribetronic list --json reports 23. Local commit. Push pending user direction (per current release flow).
…aged)
The /scribetronic:review skill gains a "delta mode" for the most common
mid-draft case: "I just wrote 1-3 paragraphs, are they OK?".
What's new
- Three new flags on /scribetronic:review (mutually exclusive):
- --since-last: diff vs the snapshot stored in
.scribetronic/snapshots/<basename>.md from the previous /review run.
First invocation per file snapshots silently and falls back to full
mode (with a note).
- --since <revspec>: git diff <revspec> -- <draft>. Examples: HEAD,
HEAD~3, main. Errors if not in a git repo.
- --since-staged: git diff --staged -- <draft>.
- New focus: continuity (delta-only). Compares the new lines against
1-2 paragraphs of surrounding context. Flags tone shifts, tense
breaks, orphan references the BEFORE didn't introduce. Silently
dropped if requested in full mode.
- Defaults adjusted by mode:
- Full mode: voice, structure, slop, hook, closer (5 focuses)
- Delta mode: voice, slop, continuity (3 focuses)
- --with-evidence adds factual to either mode.
- Subagent prompt skeleton documented for delta mode: AFTER block (the
added lines, with line numbers in the current file) is what's
reviewed; BEFORE block (1-2 paragraphs of unchanged context above and
below) is provided as anchor only — subagents are instructed not to
flag issues in BEFORE.
- Snapshot is only updated on a successful run (so a failed review
doesn't lose its reference point).
Why
- Wall time: ~5s for delta mode (3 subagents) vs ~10s for full mode (5).
- Token cost: ~80% lower per delta review (only the changed hunks +
small context, not the full draft).
- Cognitive fit: the dominant mid-draft pattern is "wrote a bit, want
feedback, keep going". Forcing a full re-review of 1500 words after
every 200-word addition is overkill.
Project template
- New packages/cli/templates/project/scribetronic/.gitignore ignoring
.scribetronic/ (the local state dir used by --since-last). Created
on init.
Other
- frontmatter description updated; argument-hint extended with the new
flags.
- "When to use which" table reorganised — delta-mode rows on top.
- New anti-patterns: don't run continuity outside delta mode; don't
snapshot in --since modes other than --since-last.
- CHANGELOG [Unreleased] entry expanded.
- Plugin repo synced (23 SKILL.md still; review/SKILL.md updated
in-place).
Tests: 106/106 still pass (skill is markdown).
E2E smoke: scribetronic init now writes scribetronic/.gitignore.
Local commit. Push pending.
…st publish
The v0.2.1 release ships everything currently in develop (plugin marketplace,
frontmatter fix, format/style decoupling, writing-style override path, agent-
friendly CLI, /review skill). This commit gets the user-facing docs ready
for that publish.
Major rewrites
- packages/cli/README.md: was completely stale ("not on npm yet (planned for
v1.0)", described init copying skills to project, missing /review, missing
the new commands). Rewritten end-to-end. This is the README that npmjs.com
shows under the package — accurate now: 23 skills, plugin marketplace, all
7 commands, scribetronic/style/writing-style.md path, --json/--yes flags.
Smaller fixes
- README.md (root): replaced 3 lingering writing-style/SKILL.md path
references with the project-override path scribetronic/style/writing-style.md.
- docs/customization.md, docs/contracts.md, docs/philosophy.md: same path
fix where the doc was talking about the user-editable file (vs the bundle
template, which keeps the legacy path).
- 24.scribetronic-plugin/README.md: 22 → 23 skill count, added /review
to the shared utilities table.
CHANGELOG
- Merged the [Unreleased] entry (the /review skill + .gitignore template)
into [0.2.1] so the release notes carry everything that's about to ship.
- [Unreleased] now only carries the v0.3.0 plan items (write Phase 4
adopting /review by default, calendar export, multi-author profiles).
- Added a one-paragraph header to [0.2.1] explaining what this first
public release bundles.
Quality
- Tests 106/106, typecheck + lint clean.
- Plugin repo already has matching content (synced + pushed in prior
commits); this commit doesn't change skills.
This is the last documentation pass before tagging v0.2.1.
…leText) Test job on Node 18 was failing because vitest v4 bundles rolldown, which imports styleText from node:util. That export was added in Node 20.12; Node 18 ships node:util without it. Changes - .github/workflows/ci.yml: matrix [18, 20, 22] → [20, 22] - packages/cli/package.json: engines.node ">=18.0.0" → ">=20.0.0" - packages/cli/README.md, CLAUDE.md, AGENTS.md, CHANGELOG.md: doc references updated. Node 18 entered maintenance LTS Oct 2024 and EOL April 2025, so this isn't a meaningful loss of coverage.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
First real release of scribetronic. Two substantive changes vs main:
Plugin marketplace distribution. Skills now ship from r-bart/scribetronic-plugin and load at runtime via
/scribetronic:<name>. CLI registers the marketplace in.claude/settings.jsonand stops copying SKILL.md into the project. New commands:update,doctor,uninstall. Workflow hooks:SessionStart(today's editorial slot) +Stop(slop-check reminder for touched drafts).Skill content decoupled from style. Every
long-form-*,short-form-*,editing-pass, andai-slop-checkSKILL.md is now format-only — no embedded author names, personal references, or "-style" labels.writing-style/SKILL.mdships as a personalization template. Result: every format skill is reusable by any writer in any niche without editing.Plus a critical fix that came from real-world smoke testing: SKILL.md frontmatter normalized to the spec-allowed keys only (
name,description,allowed-tools,argument-hint). Prior to this, 18 of 22 skills had non-spec keys and were silently rejected by Claude Code's skill loader — only 4 were actually registering as slash commands.Test plan
npm run typecheck && npm run lint && npm test && npm run build— all greeninitwrites.claude/settings.jsoncorrectly, no.claude/skills/directory created,scribetronic/scaffoldeddoctorreports the 6 expected checks (5 pass, 1 fails on missing writing-style — by design)npm pack --dry-run: 65.3 KB tarball, 48 files/plugin marketplace add r-bart/scribetronic-plugin+/plugin install scribetronic@scribetronicworks; all 22/scribetronic:*slash commands register after the v0.2.1 frontmatter fixCompanion changes
r-bart/scribetronic-plugin@d316c93synced and pushed (lockstep with this PR's0.2.1).claude/rules/skills.mddocuments the two hard constraints (frontmatter spec compliance, format ↔ style decoupling). Detection is manual code review — no list of forbidden names is checked into the repo, intentionally.🤖 Generated with Claude Code