Skip to content
Ultracite
Esc
↑↓navigate↵open⌘Jpreview

Keep OpenHands working until Ultracite passes

OpenHands puts the full root AGENTS.md into the agent’s initial system prompt. Ultracite doesn’t write an OpenHands hook, but OpenHands documents a Stop hook for this job: when the agent tries to finish, the hook runs your linter and keeps the agent working until it passes.

OpenHands by All Hands AIChecked against OpenHands 1.26.0

# Ultracite Code Standards

This project uses **Ultracite**, a zero-config preset that enforces strict code quality standards through automated formatting and linting.

## Quick Reference

- **Format code**: `npx ultracite fix`
- **Check for issues**: `npx ultracite check`
- **Diagnose setup**: `npx ultracite doctor`

Oxlint + Oxfmt (the underlying engine) provides robust linting and formatting. Most issues are automatically fixable.

…
Ultracite’s rules
Where OpenHands looks for instructions
  1. 1AGENTS.mdUltraciteFrom the working directory, and from the Git repo root if that’s different. Its full content goes into the initial system prompt.
  2. 2CLAUDE.md, GEMINI.mdAlso loaded as repository context, along with AGENT.md and .cursorrules.
  3. 3packages/*/AGENTS.mdA nested file becomes a path rule, injected the first time the agent reads, edits or creates a file under that directory.
  4. 4.agents/skills/Project skills. They win over the legacy .openhands/skills/ and .openhands/microagents/ when names clash.

How OpenHands reads the rules

OpenHands treats the root AGENTS.md as always-on repository context and nested AGENTS.md files as rules for their own directory. Skills come on top, from .agents/skills/ and the legacy .openhands/ folders.

Working directory first
Started in a subdirectory, OpenHands also checks the Git repo root, but a file in the working directory wins over the root’s file of the same kind.
Keep it short
Always-on content takes up context from the first message, so OpenHands suggests a concise AGENTS.md. Ultracite’s rules are about 120 lines.
Setup script
.openhands/setup.sh runs every time OpenHands starts work on the repo. Install dependencies there so ultracite is ready.
Hooks file
.openhands/hooks.json, committed to the repo. Hooks are active the next time OpenHands works on it.
Check it
In the CLI, /skills lists the loaded skills, hooks and MCP servers. In the Cloud, hook events show in the conversation log.
Symlinks
A CLAUDE.md symlinked to AGENTS.md is loaded once, not twice.

A Stop hook that waits for a clean check

OpenHands hooks live in .openhands/hooks.json and work in the Cloud, the CLI and the local GUI. A PostToolUse hook can’t block there, so OpenHands’ own lint example uses a Stop hook; the snippets are that example with ultracite check swapped in. Ultracite doesn’t write them for you.

#!/bin/bash
# Stop hook: Don't let the agent stop if Ultracite finds problems
cd "$OPENHANDS_PROJECT_DIR"

if ! npx ultracite check 2>&1; then
    echo '{"decision": "deny", "reason": "Ultracite found problems. Please fix them before finishing."}'
    exit 2
fi
exit 0
{
  "stop": [
    {
      "matcher": "*",
      "hooks": [
        {
          "command": ".openhands/hooks/lint_check.sh",
          "timeout": 120
        }
      ]
    }
  ]
}
  1. 01The agent edits files in its sandbox, with AGENTS.md in its system prompt.
  2. 02When it tries to finish, OpenHands runs the Stop hook, which runs npx ultracite check.
  3. 03If the check fails, the hook prints a deny decision and exits 2, and the agent keeps working.
  4. 04Once the check passes, the hook exits 0 and the agent finishes. Make the script executable with chmod +x.

Worth knowing about OpenHands

  • Nested files become path rules

    A packages/api/AGENTS.md isn’t loaded up front. OpenHands turns it into a path rule and injects it once, the first time the agent reads, edits or creates a file under packages/api/, so a package’s notes cost nothing until they’re needed.

  • Headless runs approve everything

    openhands --headless -t "…" runs without the terminal UI, for scripts and CI. It always runs in always-approve mode, which can’t be changed, and --json streams every event as JSON Lines you can parse.

  • Issues and pull requests on GitHub

    With OpenHands Cloud installed on a repository, label an issue openhands or start a comment with @openhands, and it opens a pull request when it’s done. Mention @openhands on a pull request to ask for updates.

  • The Ultracite skill

    OpenHands loads project skills from .agents/skills/, where init installs the Ultracite skill, and from the legacy .openhands/skills/, where it also goes when the project has an .openhands folder. When both copies exist, the .agents/skills/ one wins. Start a new conversation after adding it.

OpenHands questions, answered

Does OpenHands read AGENTS.md?
Yes. The root AGENTS.md is always loaded, in full, into the agent’s initial system prompt. OpenHands also recognizes AGENT.md, CLAUDE.md, GEMINI.md and .cursorrules as repository context.
How do I make OpenHands run the linter?
The rules tell it to run npx ultracite fix and npx ultracite check. To enforce that, add a Stop hook that runs ultracite check and exits 2 when it fails, so OpenHands can’t finish until the check passes.
Will Ultracite’s Claude Code hook run in OpenHands?
No. OpenHands reads hooks from .openhands/hooks.json, not .claude/settings.json. Its format accepts Claude Code’s, but its tools have different names, such as terminal rather than Bash.
Why a Stop hook instead of PostToolUse?
In OpenHands, PostToolUse hooks can’t block, so they can’t send the agent back to work. A Stop hook can: exit code 2, or a deny decision, keeps the agent going.
What happened to microagents and repo.md?
Microagents are now skills. .openhands/microagents/ still loads, but OpenHands recommends AGENTS.md for repository-wide guidance and .agents/skills/ for skills.
I use .openhands/pre-commit.sh. Should I keep it?
OpenHands suggests moving checks from .openhands/pre-commit.sh into a Stop hook, so the quality gate applies to its current agent-server-backed flows.

Ship less slop

One command sets up your linter, formatter, editor and agents. Works with Oxlint, Biome and ESLint.