Skip to content

feat: tell agents to write in Simple English, with hooks - #833

Merged
nieblara merged 5 commits into
mainfrom
cursor/simple-english-agent-guidance-e375
Oct 5, 2026
Merged

nieblara merged 5 commits into
mainfrom
cursor/simple-english-agent-guidance-e375

Conversation

@nieblara

Copy link
Copy Markdown
Contributor

Requirements

  • I have added test coverage for new or changed functionality
  • I have followed the repository's pull request submission guidelines
  • I have validated my changes against all supported platform versions

Related issues

None. The rules come from the Simple English skill, which uses the MIT license.

Describe the solution you've provided

Summary

This PR tells AI agents to write in Simple English in this repository. Simple English is plain English that follows the rules of ASD-STE100 Simplified Technical English. The rules give short sentences, active voice, one word for one meaning, and no filler words.

The PR has three parts:

  1. A copy of the Simple English skill in .agents/skills/simple-english/
  2. A new section in AGENTS.md that tells agents to use the skill
  3. Hooks for Cursor, Claude Code, and Codex that load the rules and lint Markdown files

The guidance

The new "Writing Style: Simple English" section in AGENTS.md applies to replies, Markdown files, pull request descriptions, commit messages, and new code comments. It lists the rules that agents break most often. It also tells agents not to change code, generated files, or text that their task does not touch. CLAUDE.md is a link to AGENTS.md, so Claude Code gets the same section.

The hooks

A hook is a command that an agent tool runs at a fixed point, for example at the start of a session. All the hooks run one script, .agents/skills/simple-english/scripts/hook.py. The hooks are advisory, so they never block an action.

Tool Configuration What the hooks do
Cursor .cursor/hooks.json Load the rules at session start. Lint each Markdown file after a write.
Claude Code .claude/settings.json Load the rules at session start. Lint each Markdown file after a write. Report bold text, headers, lists, and em dashes in each reply.
Codex .codex/hooks.json Load the rules at session start.

The lint reports only the lines that differ from the last commit. For example, README.md has 20 old violations today. If an agent adds one bad line, the hook reports that line only. A new file gets a full lint.

Cursor also runs the hooks in .claude/settings.json. For this case, the script finds the Cursor input and runs only the Cursor hooks. Cursor Cloud Agents do not run session start hooks, so they get the rules from AGENTS.md.

To turn off the hooks, set SIMPLE_ENGLISH_HOOKS=off.

A fix in the linter

The skill includes a linter, scripts/ste_lint.py. In the upstream version, each line number after a code block or a table is too small. In this repository, the upstream linter put 34 hits on the wrong line, in 26 of the 33 Markdown files. The copy in this PR keeps the newlines, so all hits go to the correct line. The violation counts do not change. UPSTREAM.md records this change and the steps to update the copy.

Tests

scripts/test_hook.py has 15 tests. The tests cover these areas:

  • The output format for each tool
  • The Claude Code hooks that Cursor runs
  • The lint of changed lines only, with code blocks and tables before the changed line
  • The files that the lint skips, such as CHANGELOG.md
  • The reply report for Claude Code
  • Input that is not valid JSON

To run the tests, run python3 .agents/skills/simple-english/scripts/test_hook.py. I also ran the hook on real files in this repository. I did not run the hooks in a live Cursor, Claude Code, or Codex session, because this environment has no credentials for those tools.

Describe alternatives you've considered

We did not use the upstream hook scripts. The upstream scripts need the layout of a Claude Code or Codex plugin, and they do not support Cursor.

We did not add a Cursor stop hook for the reply report. A Cursor stop hook can only start a new agent turn, and that can cause a loop.

We did not lint the full file after each edit. The full lint told agents to correct old text that their task did not touch.

Additional context

The hooks need python3. Codex runs project hooks only in a trusted project, and Codex asks you to approve each hook. Open /hooks in Codex to approve it.

Open in Web Open in Cursor 

cursoragent and others added 5 commits September 29, 2026 21:32
Copy the Simple English skill into .agents/skills/simple-english. Cursor
and Codex load project skills from .agents/skills. The files come from
commit 79b590fc8596523d92c26b1ea7e33236606ef069 with no changes. The
project uses the MIT license, and LICENSE holds the license text.

Co-authored-by: Ramon Niebla <nieblara@users.noreply.github.com>
The upstream strip_code function replaced each code block and some table
rows with one space. It removed their newlines, so each line number after
a code block or a table was too small. In this repository, 34 hits went to
the wrong line.

strip_code now keeps the newlines that it removes. The violation counts do
not change.

Co-authored-by: Ramon Niebla <nieblara@users.noreply.github.com>
Add hooks that load the Simple English rules at session start and lint
the Markdown files that an agent writes. The hooks are advisory, so they
never block an action.

One script, scripts/hook.py, serves the three tools. The lint reports only
the lines that differ from the last commit, so an agent does not rewrite
old text. Cursor also runs the hooks in .claude/settings.json. The script
finds this case and runs only the Cursor hooks.

Co-authored-by: Ramon Niebla <nieblara@users.noreply.github.com>
Add a Writing Style section to AGENTS.md. CLAUDE.md is a link to this file.
The section gives the rules that agents break most often, the text that the
rules cover, and the hooks for each tool.

Co-authored-by: Ramon Niebla <nieblara@users.noreply.github.com>
The upstream file ends with a blank line. The end-of-file-fixer pre-commit
hook requires one newline at the end of each file, so the build failed.
UPSTREAM.md now records this change.

Co-authored-by: Ramon Niebla <nieblara@users.noreply.github.com>
@nieblara
nieblara marked this pull request as ready for review October 2, 2026 16:53
@nieblara
nieblara requested a review from a team as a code owner October 2, 2026 16:53
@ld-ahartmann

Copy link
Copy Markdown
Contributor

🤔 Approving because it looks fine, but I'm actually not 100% on this one... I think we can try the simple english, but I'll say that I tried it out on cursor for a bit and was distinctly displeased with the experience I was getting using ASD-STE100, it sort of annoyed me haha.

To be clear, this is customer-facing right? Like a customer's agents will see and absorb these skills - not just ours as internal developers of the ldcli?

If so, wonder if we could run an experiment or something to see if this noticeably affects usage trends.

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes using default effort and found 2 potential issues.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, have a team admin enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit e8c770a. Configure here.

print(json.dumps({"additional_context": context}))
else:
sys.stdout.write(context)
return 0

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Codex session hook emits invalid output

High Severity

session_start writes raw text for the codex harness, but Codex parses SessionStart stdout as JSON and requires a hookSpecificOutput.additionalContext envelope. Non-JSON output fails with an invalid session-start error, so the rules never load.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit e8c770a. Configure here.

Comment thread .cursor/hooks.json
"command": "python3 .agents/skills/simple-english/scripts/hook.py post-edit --harness cursor",
"matcher": "Write",
"timeout": 10
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor lint skips file edits

Medium Severity

The Cursor postToolUse matcher is only Write, so Markdown lint does not run after StrReplace. Cursor agents use StrReplace for in-place edits, so changed-line lint never runs for the common edit path.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit e8c770a. Configure here.

@nieblara
nieblara merged commit c3e9c0f into main Oct 5, 2026
9 checks passed
@nieblara
nieblara deleted the cursor/simple-english-agent-guidance-e375 branch October 5, 2026 20:31
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants