tabras / agents.md
vvennelakanti's picture
Build Tabras card duel prototype
6bbf552
|
Raw
History Blame Contribute Delete
3.29 kB

A newer version of the Gradio SDK is available: 6.19.0

Upgrade

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

# 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.