Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .claude-plugin/marketplace.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,14 @@
},
"metadata": {
"description": "Measures prose against 13 studies of how AI and human writing differ, from word choice to sentence rhythm to story shape, then rewrites the tells out.",
"version": "0.3.0"
"version": "0.3.1"
},
"plugins": [
{
"name": "humanize",
"description": "Audits a draft layer by layer (vocabulary, punctuation, sentence shape, openers, closers, grammar, narrative, per-model habits) against 13 studies, then rewrites what it flags in the author's voice.",
"source": "./",
"version": "0.3.0",
"version": "0.3.1",
"author": { "name": "ccf" },
"license": "MIT",
"keywords": ["humanize", "writing", "prose", "editing", "style", "ai-writing", "rewriting", "linguistics"],
Expand Down
2 changes: 1 addition & 1 deletion .claude-plugin/plugin.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "humanize",
"version": "0.3.0",
"version": "0.3.1",
"description": "Audits a draft layer by layer (vocabulary, punctuation, sentence shape, openers, closers, grammar, narrative, per-model habits) against 13 studies, then rewrites what it flags in the author's voice.",
"author": { "name": "ccf" },
"license": "MIT",
Expand Down
2 changes: 1 addition & 1 deletion .codex-plugin/plugin.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "humanize",
"version": "0.3.0",
"version": "0.3.1",
"description": "Audits a draft layer by layer (vocabulary, punctuation, sentence shape, openers, closers, grammar, narrative, per-model habits) against 13 studies, then rewrites what it flags in the author's voice.",
"author": { "name": "ccf" },
"homepage": "https://github.com/ccf/humanize",
Expand Down
14 changes: 14 additions & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# Every clone gets LF, whatever the host's core.autocrlf. The Claude Desktop skill
# loader rejects SKILL.md frontmatter that arrives as CRLF (anthropics/claude-code
# #36902); tests/test_portability.py asserts no tracked text file carries a CR.
* text=auto eol=lf

# Binary files (none tracked today; listed so a future asset is never normalized)
*.png binary
*.jpg binary
*.jpeg binary
*.gif binary
*.zip binary
*.parquet binary
*.pdf binary
*.docx binary
18 changes: 17 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,21 @@ All notable changes to this project are documented here. The format follows

## [Unreleased]

## [0.3.1] - 2026-09-14

### Added
- `.gitattributes` forcing LF on every clone, and a test that no tracked text file carries a
CR: the Claude Desktop skill loader rejects CRLF frontmatter, and "Add from repository" is a
Git clone subject to the host's `core.autocrlf`.

### Changed
- README: the Claude Desktop row now leads with the repository route (macOS and Windows) and
says to restart the app after installing or updating a plugin — the `/` menu can list
`humanize:humanize` before it is invocable. The skill zip is the alternative for claude.ai
without the Desktop app.
- Acceptance record: phase-2 outcomes (Codex and Hermes installs from `main`, the 0.2.0 → 0.3.0
plugin upgrade, Desktop on both platforms) recorded in `docs/acceptance/v0.3/README.md`.

## [0.3.0] - 2026-09-14

### Added
Expand Down Expand Up @@ -115,7 +130,8 @@ Initial release (#1).
CI (pre-commit, pytest on Python 3.9 and 3.13, `claude plugin validate
--strict`), and a Bugbot review guide.

[Unreleased]: https://github.com/ccf/humanize/compare/v0.3.0...HEAD
[Unreleased]: https://github.com/ccf/humanize/compare/v0.3.1...HEAD
[0.3.1]: https://github.com/ccf/humanize/compare/v0.3.0...v0.3.1
[0.3.0]: https://github.com/ccf/humanize/compare/v0.2.0...v0.3.0
[0.2.0]: https://github.com/ccf/humanize/compare/v0.1.2...v0.2.0
[0.1.2]: https://github.com/ccf/humanize/compare/v0.1.1...v0.1.2
Expand Down
2 changes: 2 additions & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,8 @@ Never run bare `ruff format .` — ruff 0.16 formats Python fences inside
`.codex-plugin/plugin.json`, both `marketplace.json` fields, `pyproject.toml`,
and the newest CHANGELOG heading — `tests/test_portability.py` fails on drift.
- Nothing under `tests/`, `skills/**/scripts/`, or `tools/package_skill_zip.py` touches the network.
- Tracked text files are LF (`.gitattributes`: `* text=auto eol=lf`) — the Claude Desktop skill
loader rejects CRLF frontmatter; `tests/test_portability.py` fails on any CR.
- `skills/` is harness-agnostic: no harness variables (`${CLAUDE_…}`, `HERMES_SKILL_DIR`,
`CURSOR_…`, `CODEX_…`) and no install commands inside it; frontmatter is exactly the Agent
Skills fields (`argument-hint` is a hard error outside Claude Code). `tests/test_portability.py`
Expand Down
11 changes: 7 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,8 @@ recorded in `docs/acceptance/`.
| Cursor | `cp -R skills/humanize ~/.cursor/skills/` (every project) or `.cursor/skills/` (this project) | the skill appears in the `/` menu | `/humanize …` or automatically |
| Hermes Agent | `hermes skills install ccf/humanize/humanize --category writing`; in a running session, `/reload-skills` | `hermes skills list` | `/humanize …` or automatically |
| Any Agent-Skills harness | `npx skills add ccf/humanize` or `cp -R skills/humanize ~/.agents/skills/` | harness-specific | harness-specific |
| Claude Desktop — Cowork | Customize → Plugins → Add from repository `ccf/humanize` → install `humanize` | listed under Customize → Plugins | `/` or `+` picker, or automatically |
| Claude Desktop — chat (claude.ai) | Customize → Skills → upload `humanize-skill-<version>.zip` from the [latest release](https://github.com/ccf/humanize/releases); "Code execution and file creation" must be on | listed under Customize → Skills | automatically, or the sidebar `/` menu |
| Claude Desktop (macOS, Windows) | Customize → Plugins → Add from repository `ccf/humanize` → install `humanize` → restart the app | listed under Customize → Plugins; `/humanize:humanize` in the picker | `/` or `+` picker, or automatically, in chats and Cowork |
| claude.ai on the web or mobile, or without a linked repo | Customize → Skills → upload `humanize-skill-<version>.zip` from the [latest release](https://github.com/ccf/humanize/releases); "Code execution and file creation" must be on | listed under Customize → Skills | automatically, or the sidebar `/` menu |

Notes:

Expand All @@ -44,8 +44,11 @@ Notes:
skipped and the audit proceeds from reading alone. `hermes plugins install` also works on
recent builds but installs the package disabled and read-only; prefer `hermes skills install`.
Installing from a raw `SKILL.md` URL fetches one file and is not supported.
- **Claude Desktop** picks up a Cowork plugin update only when `version` changes. In claude.ai
chat the skill triggers by description; picking it from the `/` menu passes no arguments.
- **Claude Desktop** picks up a plugin update only when `version` changes, and it needs a
restart after installing or updating a plugin: until then the `/` menu can list a skill the
app cannot yet invoke ("Unknown command: /humanize:humanize"). The zip is only for claude.ai
without the Desktop app. In claude.ai chat the skill triggers by description; picking it from
the `/` menu passes no arguments.
- **Word, PDF, PowerPoint inputs.** humanize delegates extraction to the harness's document
skills. In Claude Code that is Anthropic's `document-skills` plugin (`/plugin marketplace add
anthropics/skills`, `/plugin install document-skills@anthropic-agent-skills`; its `docx` read
Expand Down
19 changes: 19 additions & 0 deletions docs/acceptance/v0.3/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -189,3 +189,22 @@ Claude Code: PASS. Codex: PASS. Cursor: SKIP (not authenticated on this machine)
Hermes: SKIP (not authenticated on this machine). Both SKIPs move to phase 2
(post-merge, pre-tag) per the design doc's Post-review amendments, and are re-run
after login, with transcripts committed to this directory.

## Phase 2 record (post-merge, 2026-09-14)

- Acceptance 3 from `main`: `codex plugin marketplace add ccf/humanize` and
`codex plugin add humanize@humanize` installed 0.3.0; `codex debug prompt-input`
lists `humanize:humanize`. Left installed.
- Acceptance 4: `hermes skills install ccf/humanize/humanize --category writing`
fetched SKILL.md, all six references, and the script (resolved through the
skills.sh registry); `hermes skills list` shows `writing/humanize` enabled.
- Acceptance 6: the installed Claude Code plugin upgraded 0.2.0 → 0.3.0 through the
root-level marketplace (`source: "./"` proven).
- Acceptance 5a: Claude Desktop → Customize → Plugins → Add from repository
`ccf/humanize` installed the plugin and the skill runs in chats on macOS and on
Windows. Windows first answered `Unknown command: /humanize:humanize` from the
picker until the app was restarted — the slash menu lists the skill before the
invocable registry has it (cf. anthropics/claude-code #62485). The README now says
to restart. Acceptance 5b (zip upload) is not needed for the Desktop app; the zip
stays on the release for claude.ai without it.
- Cursor and Hermes smoke transcripts: still pending login on this machine.
6 changes: 6 additions & 0 deletions docs/design/2026-09-14-humanize-v0.3-design.md
Original file line number Diff line number Diff line change
Expand Up @@ -457,3 +457,9 @@ is the specific source of a number or a file; the tool is described as grounded
side effect on interrupt; the raw Claude stream is written to a temp directory.
- §2B — if a harness does not show the skill's path, the model searches for `scripts/surface_scan.py`
and, failing that, skips the scan and says so.
- §6/§8 (0.3.1) — acceptance 5a passed: the Desktop app's "Add from repository" route installs the
plugin on macOS and Windows and the skill runs in chats; Windows needed an app restart before the
picker's `humanize:humanize` entry became invocable (registry lag, cf. anthropics/claude-code
#62485). The zip (5b) is the alternative for claude.ai without the Desktop app, not a requirement.
A `.gitattributes` now forces LF on every clone because the Desktop loader rejects CRLF frontmatter
(#36902) and "Add from repository" is a `git clone` subject to the host's `core.autocrlf`.
2 changes: 1 addition & 1 deletion plugin.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"$schema": "https://agent-plugins.org/schemas/1.0.0/plugin.schema.json",
"name": "humanize",
"version": "0.3.0",
"version": "0.3.1",
"description": "Audits a draft layer by layer (vocabulary, punctuation, sentence shape, openers, closers, grammar, narrative, per-model habits) against 13 studies, then rewrites what it flags in the author's voice.",
"author": { "name": "ccf" },
"license": "MIT",
Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[project]
name = "humanize-plugin"
version = "0.3.0"
version = "0.3.1"
description = "Agent skill that audits prose for AI tells and rewrites it in the author's voice, on evidence from 13 studies."
requires-python = ">=3.9"
license = "MIT"
Expand Down
27 changes: 27 additions & 0 deletions tests/test_portability.py
Original file line number Diff line number Diff line change
Expand Up @@ -237,3 +237,30 @@ def test_study_count_matches_sources():
for token in found:
value = int(token) if token.isdigit() else NUMBER_WORDS[token.lower()]
assert value == n, f"{rel} says {token}, SOURCES.md has {n}"


TEXT_SUFFIXES = {".md", ".py", ".json", ".toml", ".yml", ".yaml", ".sh", ".txt", ".csv", ".cfg"}
SKIP_DIRS = {
".git",
".venv",
"node_modules",
"dist",
"__pycache__",
".superpowers",
".pytest_cache",
}


def test_tracked_text_files_use_lf():
"""The Claude Desktop skill loader rejects CRLF frontmatter; .gitattributes forces LF."""
offenders = []
for path in ROOT.rglob("*"):
if any(part in SKIP_DIRS for part in path.parts):
continue
is_text = path.suffix in TEXT_SUFFIXES or path.name == ".gitattributes"
if not path.is_file() or not is_text:
continue
if b"\r" in path.read_bytes():
offenders.append(str(path.relative_to(ROOT)))
assert not offenders, offenders
assert "eol=lf" in (ROOT / ".gitattributes").read_text(encoding="utf-8")
2 changes: 1 addition & 1 deletion uv.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading