copydesk
v0.9.5
Published
A cross-harness prose gate for AI agents
Maintainers
Readme
CopyDesk
A prose gate and style system for AI coding agents.
It prevents violations before generation, and refuses the write when a violation slips through.
Every other prose tool reads your text after it is saved. CopyDesk works in three earlier moments: it compiles instructions into the model context before generation, it intercepts file edits to refuse violations at write time, and a pre-commit hook refuses a commit whose added Markdown breaks the rules.
| When | What happens | Who is there | |---|---|---| | Before generation | Instructions enter the model context, so bad prose is never produced | CopyDesk | | At write time | The write is refused and the model revises | CopyDesk | | Before the commit | The commit is refused when its added Markdown breaks the rules | CopyDesk | | After the file is saved | The file is scored and a fix requested | sloptrim | | In continuous integration | The build reports or fails | Vale |
What it looks like
1. Prevention (before generation)
CopyDesk generates tuned output styles and instruction blocks for your agents. The model knows your style, verbosity, and constraints before writing a single token.
Answer first, then support it.
Give the answer and one line of support.
Cut any sentence that does not change what the reader knows or does.2. Remediation (at write time)
When an agent ignores instructions during a file write, the gate refuses the operation. The agent revises immediately.
The gate blocks on new findings in the edited region, not on pre-existing errors in the file. It tells the model not to touch surrounding code or text.
You can also run CopyDesk as a standalone CLI linter:
$ copydesk check release-notes.md
release-notes.md:
3:announcing-opener:Great question — let me walk you through it. This release delivers a solid and
3:sentence-length:This release delivers a solid and significant overhaul of the export pipeline…
8:idiom:That said, we should circle back on the remaining items. As noted above, the
8:orphan-pointer:That said, we should circle back on the remaining items. As noted above, the
9:soft-offer:former approach is deprecated. Happy to walk through any of this if you'd like.Why this exists
AI coding agents produce four channels of prose: terminal chat, Markdown documentation, commit messages, and code review comments.
Most unguided agent writing shares four flaws. Sentences stretch past forty words. Openers announce what is coming instead of answering. Chat repeats answered decisions turn after turn.
Post-hoc linters catch these issues in CI or after saving. That costs a full retry round trip or reviewer attention.
Measured across 1.5 million words of real transcripts, terminal chat shows 9.14 blocking violations per 1,000 words against 5.42 in documents. Chat never becomes a saved file, so a post-hoc file linter cannot inspect it. Prevention through compiled context instructions is the only way to reach chat.
Contents
- Install
- Quickstart: Setup Wizard
- Channels
- Styles
- Usage
- Configuration
- Rules
- Setting up the gate by hand
- How it compares
- Evidence
- Project status
- Contributing
- Support
- Security
- Licence and credits
Install
npm install -g copydeskOr run directly without global installation:
npx copydesk check README.mdOr clone from source:
git clone https://github.com/carlosboeing/copydesk.git
cd copydesk
./install.shCopyDesk requires Python 3.9 or later and has zero third-party dependencies.
Quickstart: Setup Wizard
Run the interactive wizard to configure styles, channels, and hooks:
copydesk setupThe wizard guides you through three choices:
- Preset style and verbosity for each channel.
- Connected harnesses and tools.
- Configuration review and proof run.
You can also run unattended with defaults:
copydesk setup --defaults --yesTo check your installation and effective rules:
copydesk doctorTo remove all CopyDesk hooks and configurations:
copydesk uninstallManaging the commit-msg hook
copydesk setup installs the commit-msg hook into the repository you run it from. The hook subcommand manages it across every repository:
copydesk hook add # install into the current repository
copydesk hook add ~/projects/foo # or a named one
copydesk hook add --scan ~/src # offer every repository one level under ~/src
copydesk hook list # every recorded repository and its state
copydesk hook remove --all # remove them allA repository whose commit-msg hook already exists is never overwritten: hook add offers to append CopyDesk's block instead, and verifies by a test run that the block is reached. Every install is recorded in $XDG_STATE_HOME/copydesk/hooks.json, so uninstall can offer to remove the hooks in your other repositories too.
Managing the pre-commit hook
The commit-msg gate checks message prose. The pre-commit gate checks the Markdown a commit adds:
copydesk install --git-hookThe hook runs copydesk check --staged before every commit. It judges the lines the commit adds, compared against HEAD.
Touching a clean paragraph passes no matter what else the file hides. An added banned word refuses the commit, and a deletion blocks only for a rule HEAD did not already break. Staged content is checked, so uncommitted edits in your working tree are not judged.
To commit anyway:
git commit --no-verifyThe same instruction lives inside the installed hook, so it is there when you need it. Findings at warn severity print but never block, whatever your configuration says about blocking. A missing copydesk binary or an internal error lets the commit through rather than bricking the repository.
A pre-commit hook CopyDesk did not write is never overwritten: the installer prints the lines to append instead, chaining the check into your own script. Running the command again refreshes a hook CopyDesk wrote. To remove it, delete .git/hooks/pre-commit, or the file under core.hooksPath if you set one.
Channels
CopyDesk divides agent writing into four channels:
| Channel | Medium | Gate mechanism | Default style |
|---|---|---|---|
| chat | Terminal conversational replies | Stop hook, recording only by default | plain (low verbosity) |
| documents | Markdown files on disk | PreToolUse write/edit hook | plain (high verbosity) |
| commits | Git commit messages | commit-msg git hook | engineer (low verbosity) |
| reviews | PR and code review markdown | Configured match file patterns | plain (medium verbosity) |
The chat gate records what a reply broke and does not refuse the reply. Claude Code appends a replacement message and leaves the refused one on screen, so a refusal shows the reader the same answer twice. To refuse instead, run copydesk set channels.chat.gate=block.
Read more in docs/channels.md.
Styles
CopyDesk ships four base styles:
| Style | Purpose | Best suited for |
|---|---|---|
| plain | Answer first, concise supporting facts | Day-to-day coding, technical documentation |
| engineer | Terse procedures, tables, minimal prose | API references, runbooks, schemas |
| editorial | Narrative explanations, flowing paragraphs | Thought leadership, blog posts |
| general | Plain terms with every specialized word glossed | Onboarding guides, non-technical docs |
Read more in docs/styles.md.
Usage
Check files or standard input:
copydesk check docs/guide.md CHANGELOG.md
cat draft.md | copydesk check -
copydesk check --commit-msg .git/COMMIT_EDITMSG
copydesk check --staged # lint what the index adds against HEAD
copydesk install --git-hook # run that automatically before every commitInspect rules and resolution:
copydesk doctor # explain active settings and health
copydesk doctor docs/guide.md # explain rules for a specific file
copydesk doctor --rules # list all rules and guidance parametersChange a chat setting quickly:
copydesk set channels.chat.verbosity=medium
copydesk set channels.chat.gate=block # refuse a reply instead of recording itView local gate telemetry:
copydesk stats # activity summary
copydesk stats --since 30d --json # JSON format
copydesk report --out report.md # detailed markdown reportExit codes:
| Code | Meaning |
|---|---|
| 0 | Clean, or warnings only |
| 1 | Blocking prose findings |
| 2 | Hook blocked a write |
| 64 | Usage error |
| 70 | Internal error (fails open for git commits) |
Configuration
Configuration is optional. By default, the plain preset applies.
CopyDesk merges configuration across three locations:
| Layer | Path | Purpose |
|---|---|---|
| User | ~/.config/copydesk/config.json | Personal defaults |
| Project | copydesk.config.json | Repository standards |
| Local | copydesk.local.json | Local overrides |
JSON with comments (JSONC) is supported.
{
"$schema": "https://raw.githubusercontent.com/carlosboeing/copydesk/v0/copydesk.schema.json",
"version": 1,
"channels": {
"chat": { "style": "plain", "verbosity": "low" },
"documents": { "style": "engineer" }
},
"paths": {
"ignore": [".workbench/**", "drafts/**"],
"warn": ["CHANGELOG.md"]
},
"rules": {
"sentence-length": { "severity": "warn", "max": 30 },
"banned-word": { "add": ["synergy"], "remove": ["solid"] },
"unglossed-term": { "add": ["React", "Postgres"] }
}
}Full details are in docs/configuration.md.
Rules
15 rules across three groups:
| Group | Rules |
|---|---|
| Pattern | banned-word, idiom, soft-offer, announcing-opener, contrast-construction, orphan-pointer, verb-jargon |
| Metric | sentence-length, paragraph-length, avg-sentence-length, long-sentence-rate, sentence-variation, list-dominated, unglossed-term |
| Structural | nested-table |
Every rule and parameter is documented in docs/rules.md.
Setting up the gate by hand
copydesk setup handles installation automatically. If you prefer manual setup for Claude Code:
Copy hooks and rules:
mkdir -p ~/.claude/hooks/copydesk/rules ~/.claude/output-styles cp hooks/gate.sh hooks/reminder.sh lib/linter.py ~/.claude/hooks/copydesk/ cp rules/plain.json ~/.claude/hooks/copydesk/rules/ chmod +x ~/.claude/hooks/copydesk/gate.sh ~/.claude/hooks/copydesk/reminder.shRegister in
~/.claude/settings.json:{ "hooks": { "PreToolUse": [ { "matcher": "Write|Edit", "hooks": [{ "type": "command", "command": "~/.claude/hooks/copydesk/gate.sh" }] } ], "UserPromptSubmit": [ { "hooks": [{ "type": "command", "command": "~/.claude/hooks/copydesk/reminder.sh" }] } ] } }Run
copydesk doctorto verify registration.
How it compares
| When | What happens | Who is there | |---|---|---| | Before generation | Instructions enter the model context | CopyDesk | | At write time | The write is refused | CopyDesk | | Before the commit | The commit is refused when its added Markdown breaks the rules | CopyDesk | | After the file is saved | The file is scored | sloptrim | | In continuous integration | The build reports or fails | Vale |
Where CopyDesk differs:
| Tool | Differences | |---|---| | Vale | Markup-aware parsing, official style packages, and editor integrations. | | sloptrim | Supports 20+ document formats and calculates holistic scores. | | CopyDesk | Real-time latency with zero runtime dependencies and fail-open guarantees. |
Evidence
- Observational baseline: Analysis across 1,556,107 words of chat and 626,153 words of Markdown.
- Prevention baseline: The corpus blocking rate and the per-rule false-positive rates.
copydesk reportnames this page as the source of its Prevention section. - Gate baseline: Multi-turn session evaluations from 2026-08-17, tracking rule enforcement and instruction decay over time. The prevention baseline re-measures the same transcripts.
Project status
0.9.5, pre-1.0. The CLI commands, config schema, rule identifiers, and channel definitions are stable.
See docs/ROADMAP.md for future plans and CHANGELOG.md for release history.
Contributing
See CONTRIBUTING.md for test execution and contribution guidelines.
Support
Use SUPPORT.md for usage questions, bug reports, and feature requests. The issue tracker is the public place for questions and reports.
Security
CopyDesk runs locally and makes no outbound network connections. Document contents never leave your machine. See SECURITY.md for private vulnerability reports.
Licence and credits
MIT. See LICENSE. Notices for adapted third-party code are in THIRD_PARTY_NOTICES.md.
lib/linter.py is adapted from AminBlg/SimpleEnglish (MIT).
