Improving Example Sentences with Claude Skills, Part 2: Sandboxed Runs and Automated Review
In Part 1 we built the improve-example-sentence skill: one invocation, one PR, one focused diff. The skill is already fully autonomous. It picks its own target, writes the replacement, opens the PR, and returns to main without asking for permission at any step.
The problem is that someone still has to sit there and invoke it. And once the PR is open, someone has to review and merge it.
This post covers how we solved both halves of that with a Docker sandbox and a second skill.
Running the skill without babysitting it
The skill does everything locally. It reads CSVs, writes files, and calls gh pr create. That means it can run completely unattended, but it also means an unconstrained agent has write access to your working tree, your git history, and your shell.
Running it inside a Docker sandbox gives you a contained environment: a fresh clone of the repo, network access limited to what the skill actually needs (GitHub and the Anthropic API), and nothing else reachable. When Claude runs in the sandbox, the worst outcome is a bad PR, which we can close. It can't touch anything outside the container.
The result is that running a sentence improvement goes from "open Claude Code, invoke the skill, watch it work" to just invoking it and walking away. The PR shows up when it's done.
Claude reviewing Claude
An open PR still needs to be reviewed and merged. We built a second skill for that: review-improve-sentence-prs.
The review skill goes through every open improve-sentence-* PR and for each one:
- Reads the PR body: the word, the old sentence, the new sentence, and the reason for the change
- Evaluates the change. Is the old sentence genuinely broken? Is the new one grammatically correct, natural, and does it actually demonstrate the word's meaning?
- Posts a justification comment explaining specifically why the change is an improvement, referencing the actual words and constructions involved
- Merges the PR
If something looks wrong, say the new sentence introduces its own error or the translation doesn't match, it skips that PR, leaves it open, and reports it at the end.
So each merged PR ends up with a comment explaining the reasoning, written at review time with fresh eyes rather than baked into the original skill's output. That separation is what makes "Claude reviewing Claude" work at all. The review runs in its own context and asks a different question (is this actually correct?) instead of validating its own prior work.
How we actually run it
The improvement skill can be invoked by a cron job or a background agent. The review skill runs manually whenever we want to clear the queue, or on a schedule too.
Day to day, that leaves three things to do: set the threshold ("fix everything below a 4"), decide when to run the review pass, and look at the PRs the review skill flagged instead of merging. The rubrics in the skills handle the rest, which is the whole reason we wrote them down as rubrics.