Skip to content

Course · OpenCode · Rules (AGENTS.md)

Write feedmill's AGENTS.md

Running OpenCode against a real repository comes with a quiet tax: the conventions that live in your head, not in the code. feedmill - the course’s illustrative Go feed aggregator - carries two of them. Timestamps are stored and compared in UTC, and any new fetch path has to respect the per-source rate-limit delay, or the upstream feeds start returning 429s. Neither rule is written down anywhere the agent can read, so every session starts the same way: you remind it of both, it honors them for that session, the session ends, and the knowledge goes with it. The next session, you’re typing the same two sentences again before you can ask for anything real.

That’s not a prompting problem you fix by prompting harder. It’s a missing file. The two rules belong to the repo, not to your memory - so they should live in the repo, where OpenCode loads them at the start of every session without being told.

OpenCode has no Rules file - AGENTS.md is it

Section titled “OpenCode has no Rules file - AGENTS.md is it”

If you’ve come from Claude Code you may be looking for a dedicated behavioral-rules file. There isn’t one. OpenCode does not have a separate “Rules” file as its own primitive - AGENTS.md is the rules layer. (A repo that already keeps a project CLAUDE.md still gets its rules: OpenCode falls back to that file when it finds no AGENTS.md, and stops reading it once an AGENTS.md exists; rules documentation, as of October 2026.) That’s the whole mechanism, and it’s deliberately the same AGENTS.md that Codex reads: OpenCode is another implementation of the agents.md spec, so a file you write here is portable to Codex with no changes. One file, two tools, and anyone who clones feedmill inherits the same standing instructions you do.

OpenCode reads it from two places (as of October 2026; rules documentation):

  • ./AGENTS.md - at the project root, committed to the repo. This is where feedmill’s rules go: they’re true for everyone who touches the code.
  • ~/.config/opencode/AGENTS.md - user-wide, applied across every project on your machine. This is for your personal preferences (how you like commits worded, say), not facts about a specific codebase.

The UTC-and-rate-limit rules are facts about feedmill, so they go in the project-root file. Keep the distinction sharp - a feedmill truth in your user-wide file would silently stop traveling the moment a teammate clones the repo, which is exactly the failure you’re trying to kill. The two files don’t compete: OpenCode loads the global file and the project file and combines them, so your personal preferences and the repo’s rules both apply at once.

You could open an editor and write the file by hand. But OpenCode can read the repo and draft it for you, which on code you did not write is the better first move - it’ll surface conventions you haven’t noticed yet. Run /init at the prompt - the built-in command that creates or updates AGENTS.md (as of October 2026; rules documentation). An illustrative exchange:

> /init
• Scanning feedmill…
Read README.md, go.mod, main.go, cmd/sync/main.go, internal/ (12 files)
I've generated AGENTS.md from the codebase. It covers the build/test
commands, the CLI-plus-sync-server layout, and the storage and
fetch conventions I could infer from the code.
⏵ Write AGENTS.md

/init scans the important files in the repo, asks a couple of targeted questions when the code can’t answer them, and then creates or updates AGENTS.md with concise project-specific guidance - build commands, architecture, the conventions it can read off the source. It’s a draft, not gospel. The agent can infer that feedmill is a Go CLI with a sync server, but it can’t always infer a rule that only exists in the original author’s head - like “fetches respect the rate-limit delay,” which is a contract with upstream servers, not something written plainly in one function. So you read what it wrote, then add the rules it couldn’t know.

If your repo already has an AGENTS.md, /init updates it; keep the useful rules it already holds. Open the result and ensure it contains the standing facts below. Keep them terse and imperative - this is instruction, not documentation:

## Conventions
- All timestamps are stored and compared in UTC. Parse incoming feed
dates to UTC at ingest; never store a feed's local time.
- Every fetch must respect the per-source rate-limit delay. Route new
fetch code through internal/sync/limiter.go - do not call the HTTP
client directly, or upstreams start returning 429s.

Two rules, the two you were re-typing. Commit the file and the tax is gone - OpenCode now loads AGENTS.md in this repo at the start of every session, so the rules are in context from the first message without you saying a word. Watch it land on the very next task. One note first, because the transcript shows something a stock config would not: build is OpenCode’s default coding agent, and out of the box its edits land without asking, but this exchange runs against a repo whose opencode.json sets agent.build.permission.edit to ask, the gate the first-change lesson sets up. That is why the edit asks before it lands (permissions documentation, as of October 2026). An illustrative exchange:

build ›
> add a fetcher that downloads one Atom feed URL, parses it, and
normalizes the entries
• Read internal/sync/limiter.go, internal/parse/atom.go (2 files)
Following the repo conventions: I'll parse each entry's updated
timestamp to UTC at ingest, and route the new fetcher through the
shared limiter rather than calling the HTTP client directly.
⏵ Create internal/sync/fetch.go
Permission required
Allow once Allow always Reject

The rules were already in its context before its first tool call, and the proposal names both back to you - UTC at ingest, fetch through the limiter - on a task where you never mentioned either. That’s the payoff: the rule now lives with the code, in context on every clone of the repo and portable to Codex unchanged, instead of living in a sentence you have to remember to type.

Keep one distinction straight. AGENTS.md is guidance: the model usually follows it, but nothing in OpenCode blocks an edit that calls the HTTP client directly. The ask gate above is enforcement of a different kind. It holds every build edit until you approve it, and it covers only the edit tools.

Not every sentence you catch yourself repeating deserves this treatment, though. The file loads at the start of every session, so every line pays rent in the window from message one - and a line the model would have honored anyway buys nothing. A line that’s true only this week buys a week of value, then keeps charging rent after it goes stale; the ledger below counts a single week, so it still credits that week’s savings. The rules you just wrote earn their place because each one replaces a mistake you’d otherwise be correcting mid-task, session after session. Seven candidate lines from another project; toggle each in and watch the ledger decide which earn their slot:

Seven candidate lines for your rules file. Toggle each one in and see whether it earns its slot over a week of sessions.

always-loaded cost480 tok/weekre-teaching avoided5.6k tok/weeknet+5.1k tok/week

Net positive - but 1 line is paying rent with the durable facts’ savings. Cut the amber ones; the ledger only improves.

Numbers are illustrative - the ratios are the point: a re-teach cycle (wrong attempt, correction, redo) dwarfs the line that prevents it. Assumes 10 sessions a week, the file loaded at the start of each.

One file at the project root is the simple case. Real repos have subdirectories, and OpenCode’s discovery walks up from the directory you start it in to the repo root, loading every AGENTS.md on that path (as of October 2026; rules documentation, with the stacking confirmed in the source). A nested AGENTS.md therefore adds to the root file when you start inside its directory, and is not on the walk when you start above it (it attaches later, if the agent reads a file in that directory). If you need a set that loads no matter where you start, list the files in opencode.json’s instructions field. Next: discovery and the nesting walk.