Skip to content

Instantly share code, notes, and snippets.

@jamonholmgren
Created February 26, 2026 20:37
Show Gist options
  • Select an option

  • Save jamonholmgren/35771895c486eace29f22f6377ec8019 to your computer and use it in GitHub Desktop.

Select an option

Save jamonholmgren/35771895c486eace29f22f6377ec8019 to your computer and use it in GitHub Desktop.
My current AGENTS.md for Into the Dawn

AGENTS

Mode

Determine your mode from the user's request before doing anything else:

  • Plan — User describes a feature, bug, or idea. The Project Manager reads GAME_DESIGN + PROGRESS + TODOS, consults relevant experts to flesh out the plan, produces concrete steps, creates/updates TODO entries, and stops for user review. No code yet.
  • Build — User says "do this" or points at a specific TODO. The Project Manager identifies which experts and docs are relevant, gets their input on approach, then implements. After implementation, experts review and the PM runs the quality checklist. Lint and commit.
  • Review — User asks for review, or you're finishing a build. The Project Manager runs relevant experts against recent changes and produces a structured report with an overall assessment.
  • Loop — User explicitly requests the agent loop. Read Docs/AGENT_LOOP.md and follow it.

If a mode shift is needed mid-task (e.g., Build reveals a design question), pause and switch to the appropriate mode for that question before continuing.

Doc Routing

Load docs based on your mode. Don't load everything — only what you need.

Plan mode

  • Docs/GAME_DESIGN.md — vision, game loop, mission types (follow its Related Documents links if relevant)
  • Docs/PROGRESS.md — what's done vs planned
  • Docs/TODOS.md — existing task backlog

Build mode (load only what's relevant to the task)

  • Docs/GAME_ARCHITECTURE.md — always skim for architecture context
  • Docs/AGENTS_2D.md — if touching UI / menus / HUD / controls
  • Docs/AGENTS_3D.md — if touching 3D / physics / visuals
  • Docs/MENU_THEMING.md — if touching menu styling
  • Docs/PERFORMANCE_GUIDE.md — if touching frame-sensitive or per-frame code
  • Docs/TESTING.md — if writing or updating tests
  • Docs/MULTIPLAYER.md — if touching any synced state, RPCs, or authority
  • Other system docs (MISSILE_SYSTEM.md, COUNTERMEASURES_SYSTEM.md, AUTOPILOT_SYSTEM.md, RADAR_SCAN_SYSTEM.md, etc.) — if touching that system
  • Scripts/GameSetup.gd — good example of the static helper class pattern

Review mode

  • Recent git log --oneline -20 and git diff to understand what changed
  • Expert review panel (below)
  • Quality checklist (below)

Project Manager

The Project Manager coordinates the expert panel across all modes. The PM:

  • Plan mode: Reads design docs, identifies which experts are relevant, consults them to flesh out the plan (not just rubber-stamp it after), and synthesizes their input into concrete steps.
  • Build mode: Before implementation, gets expert input on approach. After implementation, runs the relevant experts for review and the quality checklist.
  • Review mode: Runs all relevant experts, synthesizes their feedback into a structured report with an overall assessment (e.g., "looks great, no notes" or "solid work with a few issues to address" or "needs significant rework").

The PM ensures experts update their owned docs when they discover something worth documenting. This is how docs self-heal.

Expert Review Panel

The PM activates relevant experts — not all 8 every time, just those whose area overlaps with the work. Each expert provides concise, critical-but-constructive feedback (1-3 lines).

1. Godot/GDScript Expert

GDScript 4.6+ idioms, Godot engine APIs, performance patterns. Catches non-idiomatic code, missed engine features, and performance pitfalls.

  • Owns: PERFORMANCE_GUIDE.md, FRAME_TIMING.md, AGENTS_3D.md
  • Reads: AGENTS_2D.md, any system doc for the area being changed

2. Army Aviation Expert

US Army helicopter operations, systems accuracy, realistic-but-fun tradeoffs. Insists on accuracy when it's easy to fold in; accepts game-fun tradeoffs when justified and noted. Knows AH-64D Apache systems well and will expand to other airframes as they become flyable.

  • Owns: MISSILE_SYSTEM.md, COUNTERMEASURES_SYSTEM.md, AUTOPILOT_SYSTEM.md, RADAR_SCAN_SYSTEM.md, RADIO_COMMS_SYSTEM.md, WEAPON_DATA_MODELING.md
  • Apache-specific knowledge lives in the owned docs for now; per-helicopter docs split when a second airframe becomes flyable

3. Game Design Expert

Knows GAME_DESIGN.md inside and out. Protects the design intent — pushes back when implementation drifts from the vision. Understands the game loop, progression, and what makes the game fun.

  • Owns: GAME_DESIGN.md, PROGRESS.md, PILOT_PROGRESSION_AND_AWARDS.md, GS2000_SCORING.md, WEATHER_SYSTEM.md

4. UX Expert

User flows, interaction design, HUD clarity, menu polish. Reviews any UI, control, or HUD changes for usability. Thinks about what the player sees and feels.

  • Owns: HUD_SYSTEM.md, MENU_THEMING.md, AGENTS_2D.md

5. Systems Architect

High-level code architecture, system boundaries, data flow, responsibility placement. Catches wrong-object placement, state bloat, responsibility drift, and coupling issues.

  • Owns: GAME_ARCHITECTURE.md, UNIT_DATA_MODELING.md, ACCOUNTS_PLATOONS_PILOTS.md, NPC_SYSTEM.md, NPC_VEHICLE_CHARACTERS.md

6. QA Engineer

Test coverage, test design, agent self-testing. Advocates for automated tests and ensures agents run tests before returning work. Suggests new tests when coverage gaps are apparent. For test selection guidance, see TESTING.md.

  • Owns: TESTING.md

7. Multiplayer Expert

Sync patterns, authority model, disconnect/reconnect edge cases, RPC design. Reviews any code that touches networked state, RPCs, or authority.

  • Owns: MULTIPLAYER.md

Quality Checklist

The PM runs this before returning work in Build or Review mode:

  • Derived state? Don't add state vars when you can derive from existing state elsewhere.
  • Right object? UI displays state, Logic owns state. Is the code in the right place?
  • File size? If a file is growing past ~200 lines, extract into a static helper class.
  • Doc impact? Did the relevant expert update their owned docs?
  • Lint clean? Run python3 Tools/gdlint.py on changed files.
  • Tests? Did you run relevant tests or add new ones? (Run TestQuickFlow for fast validation; run system-specific tests if they exist.)

Scene Files (.tscn)

  • MAY edit property values (colors, sizes, margins, text) if no node/resource structure or reference changes
  • Do NOT add/delete nodes, change node/resource IDs or uids, or edit unique_id

Project

  • Scripts in Scripts/, Scenes in Scenes/
  • @Game.gd — main game controller; @Me.gd — local player controller; @Lobby.gd — multiplayer (being replaced)

Docs

  • When editing docs, re-read for flow; prefer rewriting whole sections over incremental search/replace
  • Don't copy code into docs — point to source files. Listing public API signatures is fine; full implementations rot.

Code organization

  • UI (menus, HUD, controls): display state, handle input, call logic. Logic (Game, Me, Lobby, Mission): game state, networking. Data (Mission, HeliData): persistence, serialization, validation.
  • Extract to logic when: affects game state, shared across UIs, or networking/persistence. Keep inline for: display-only, UI-only state, trivial pass-through.
  • Static helpers: static funcs only, extend Object. RPCs/emit in main objects (or dedicated child e.g. GameRPC.gd).

GDScript best practices

  • Explicit types always: var x: int = 1 not var x := 1; type params and return values
  • Node access: get_node() / get_node_or_null() / @onready — never $NodeName
  • 1-line guards: if not visible: return. For example, if you can, avoid this:
func _process(delta: float) -> void:
  if tracked_missile:
    _update_missile_view()
    return

Instead, do this:

func _process(delta: float) -> void:
  if not tracked_missile: return
  _update_missile_view()

This will work because under the project settings, you are allowed to return from a void function, regardless of what's returned.

  • Add assert()s for nulls; if >1 assert in a fn, combine: assert(Valid.thing(args))
  • Class member order: class_name+extends, doc comment, signals, consts, @onready, @export, public vars, private vars, built-ins (_notification first, then _ready/_process/_physics_process/_input/etc, _exit_tree), public methods, private methods (underscore-prefixed)
  • Built-ins and public methods: ~5 lines max, prefer 1-liners: func _ready() -> void: _setup()
  • Keep code at same abstraction level; delegate deeper work to private helpers
  • Private methods >10 lines → extract into static helper classes:
class_name Radar extends Node
func _ready() -> void: RadarUI.setup()
func target_unit(unit: Unit3D) -> void: RadarTargeting._target_unit(unit)

Helper static methods are still underscore-prefixed/private, only called from same group. Public API goes through the main class. Codebase doesn't follow this consistently yet — help clean up as you go.

  • Extract predicates into _is_* / _can_* helpers so loops stay clean
  • Prefer signal connections over await for deferred work — avoids dangling coroutines
  • Fix type safety at source (casts + asserts) rather than @warning_ignore
  • Descriptive parameter names (e.g. hit_unit not body)
  • Every instantiated class needs: func _notification(what: int) -> void: assert(JamminPerf.alive(&"ClassName", what)) — see Docs/PERFORMANCE_GUIDE.md

Changes

  • Don't maintain backwards compatibility with old code unless you're in the middle of a large refactor that has future stages where the code will be removed. This is a new project, not a legacy one, and hasn't been released yet. We are trying to remove tech debt, not add to it. And we will take the time to do it right.
  • Avoid adding more and more and more state variables to classes. Generally speaking, you can either use an enum or StringName for multiple state options, or better yet derive the state from already existant state elsewhere.

Linting

  • After editing .gd files: python3 Tools/gdlint.py Scripts/ChangedFile.gd (or no args for all)
  • Uses Godot LSP on port 6008 (or starts headless). Fix ERRORs before done; review WARNINGs for type safety.

When corrected

  • Acknowledge and apply. If recurring pattern, suggest a concise new/updated rule. No rules for one-off corrections.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment