Traditional docs are written for humans who browse, skim, and ask follow-up questions. LLMs need something different.
"You'll want to check the wiki for how auth works, but I think it's outdated. Ask Sarah, she knows the current setup."
"The README has some info but we changed that last quarter. Look at the PR comments for the real context."
.llm-docs/ lives in your repo. It's modular, topic-based, and optimized for machines to load exactly what they need—nothing more.
# ticket-worker Welcome to ticket-worker! This project started as a way to automate GitHub issue processing. We use Python and follow clean architecture principles inspired by Cosmic Python. The main entry point is in the entrypoints folder, but you'll also want to check out the service layer for the core business logic. For more context on why we built it this way, see the original RFC in our Notion... [500 more words of context and history]
# ticket-worker Purpose: Autonomous GitHub issue executor Language: Python 3.11+ / asyncio Architecture: Hexagonal (Cosmic Python) UI: Textual TUI ## Where Things Live Orchestration: service_layer/worker.py GitHub API: adapters/github/repository.py Claude Code: adapters/claude_code/agent.py State/DB: adapters/sqlite_state/repository.py TUI: entrypoints/tui.py Domain: domain/model.py
"Hey, don't use subprocess.run() in the agent code, it blocks the event loop" "Oh yeah I learned that the hard way last week lol" "Should we document that somewhere?" "Probably" [lost in chat history forever]
## Never Synchronous Subprocess
Never subprocess.run() — always use
asyncio.create_subprocess_exec()
Why: Blocks event loop, breaks TUI
Location: claude_code/agent.py,
all git operations
# We use immutable state transitions here # See ticket.py for more info # Actually I think we changed this? ticket.state = TicketState.IN_PROGRESS # TODO: is this right? Ask team
## Semi-Immutable Domain Objects
State changes return new instances.
# Correct
ticket = ticket.transition_to(
TicketState.IN_PROGRESS
)
# Wrong - direct mutation forbidden
# ticket.state = TicketState.IN_PROGRESS
Used by: Ticket entity, state machine
Each file stands alone. No "see above" or "as mentioned earlier." The LLM might only load one file—it needs to work without chasing references.
State what humans "just know." LLMs lack tribal knowledge. If your team knows "we always use factory pattern for services"—write it down.
Don't just document what the code does. Explain why it's that way. "We use retry logic here because the upstream API has 2% timeout rate."
Show what NOT to do. "Don't use synchronous calls here—it blocks the event loop." Preventing mistakes is as valuable as showing the right path.
Modular files mean the LLM grabs patterns.md for a refactor, gotchas.md before making changes. No wasted context.
No prose, no history, no fluff. Just the facts an LLM needs to do the job right.
Lives in your repo alongside the code. Updated in the same PR as the feature. No separate wiki to forget about.
Launch ticket-worker and it detects missing docs. One prompt, and it analyzes your codebase, identifies patterns, and generates your initial .llm-docs/ structure. No setup commands to remember.
When ticket-worker completes a feature, it updates the relevant docs. New pattern discovered? Added to patterns.md. Hit a gotcha? Documented in gotchas.md. New module? Gets its own area file.
The more tickets ticket-worker completes, the smarter your .llm-docs/ becomes. Each PR includes doc updates alongside code changes.
First run creates your docs. Every ticket keeps them current.