tabras / agents.md
vvennelakanti's picture
Build Tabras card duel prototype
6bbf552
|
Raw
History Blame Contribute Delete
3.29 kB
# AGENTS.md β€” Tabras
Engineering conventions for any agent or contributor working in this repo. Read alongside `README.md` (the design spec). README says *what* to build; this says *how* to write it.
## Non-negotiables
### Tests accompany all code
- No code lands without tests. A feature and its tests are one unit of work, written together β€” not "tests later."
- The deterministic core (`primitives.py`, `budget.py`, `game.py`) is pure logic with no model calls β€” it is fully testable and MUST be fully tested. This is where bugs hide and where balance lives.
- Model-dependent code (`generator.py`, `boss.py`) is tested by mocking the model: assert the tool-call schema, the deck-context wiring, and that engine numbers (not model output) set magnitudes. Never test against live model output.
### Coverage is the bloat metric
- Track code coverage on every change. Treat uncovered lines as **bloat**: if coverage is 50%, half the code is untested weight that should either be tested or deleted.
- Target high coverage on the deterministic core specifically β€” it's pure and has no excuse to be uncovered.
- Coverage is a deletion signal, not just a test signal: uncovered code is a prompt to ask "is this needed at all?"
### Functions do one thing
- One function, one responsibility. If a function does two things, it's two functions.
- As simple as possible, complex only where the problem genuinely requires it. Reach for complexity reluctantly and only when the domain demands it.
- A function you can't describe in one line (see comments) is doing too much β€” split it.
### Terse, readable code
- Terseness in service of readability, never against it. Shorter is better *only* when it reads more clearly.
- No cleverness that costs a reader a second look. Obvious beats impressive.
- Delete aggressively. The best code is no code; the second best is code that's plainly necessary.
### Comments: one line, at the function line
- One-line comment at the function definition stating what it does. That's the default.
- No block comments narrating internals, no inline play-by-play. If the body needs explaining, the function is too complex β€” simplify it instead of annotating it.
- Comments state *what/why* at the boundary, never *how* line-by-line (the code is the how).
## In practice
- The one-line function comment and the "describe in one line" rule are the same rule: if you can't write the comment, the function isn't doing one thing.
- Coverage + terseness + one-thing functions reinforce each other: small single-purpose functions are trivial to test, which drives coverage, which exposes bloat to delete.
- When in doubt: smaller function, clearer name, a test, delete the rest.
## What this looks like
```python
# Convert a card's energy cost into its point budget.
def budget_for(cost: int) -> int:
return cost
```
Single purpose, one-line comment at the definition, terse, testable. A companion test asserts the mapping. No internal commentary.
## Order of work (per the README build order)
Each step ships with its tests before the next begins:
`primitives.py` β†’ `budget.py` β†’ `generator.py` + `game.py` β†’ **playtest** β†’ `boss.py` β†’ `draft.py` β†’ art β†’ fine-tune.
Do not move to the next file until the current one is tested and covered.