GMLoop

July 8, 2026 · View on GitHub

This repository is the source monorepo for various GameMaker Language tools, including:

Table of contents

Formatter at a glance

Formatter (@gmloop/format) does layout/canonical rendering only (whitespace, semicolons, etc). It does not rewrite code or change semantics.

// input
function demo(){var stats={}
stats.hp=100; stats.mp=50; return stats;}

// output
function demo() {
    var stats = {};
    stats.hp = 100;
    stats.mp = 50;
    return stats;
}

Lint (lint --write) does single-file-scoped semantic/content rewrites (rule-owned).

Quick start

1) Prerequisites

  • Node.js >=25.0.0 (matches the pinned workspace default in .nvmrc)
  • pnpm (corepack enable pnpm)

2) Clone and install

git clone https://github.com/SimulatorLife/GMLoop.git
cd GMLoop
git submodule update --init --recursive
nvm use
pnpm install
pnpm run cli -- --help

3) Run baseline validation

pnpm run build:ts
pnpm run lint:quiet

Need contributor-focused setup and validation expectations? Continue with docs/contributor-onboarding.md. For a guided docs tour, start with the documentation index.

If you're planning architecture or boundary changes, read docs/target-state.md before implementing so parser/core/format ownership remains aligned.

Format from a local clone

Use the repo CLI wrapper to format any GameMaker project path:

# format writes changes (positional path or --path option)
pnpm run cli -- format /absolute/path/to/MyGame
pnpm run cli -- format --path /absolute/path/to/MyGame

# check mode (no writes)
pnpm run cli -- format /absolute/path/to/MyGame --check

format:gml now targets .gml files only. The old --extensions option and PRETTIER_PLUGIN_GML_DEFAULT_EXTENSIONS override were removed because GameMaker Language source is canonical .gml, and extension configurability created unnecessary ambiguity.

Lint from a local clone

# diagnostics only
pnpm run cli -- lint /absolute/path/to/MyGame

# diagnostics + autofix
pnpm run cli -- lint /absolute/path/to/MyGame --write

Parse from a local clone

# write AST JSON to stdout
pnpm run cli -- parse --path /absolute/path/to/MyGame/scripts/demo.gml

# write sibling *.ast.json files
pnpm run cli -- parse --write --path /absolute/path/to/MyGame

Refactor from a local clone

The refactor workspace implements a GML-native Collection API (similar to jscodeshift) for atomic cross-file transactions and metadata edits.

# preview rename (dry-run is the default; no files are written without --write)
pnpm run cli -- refactor --old-name player_hp --new-name playerHealth

# apply rename
pnpm run cli -- refactor --old-name player_hp --new-name playerHealth --write

Transpile from a local clone

# dry-run transpile (prints JavaScript to stdout)
pnpm run cli -- transpile --path /absolute/path/to/MyGame/scripts/scr_demo/scr_demo.gml

# write .js outputs for all discovered .gml files under the target path
pnpm run cli -- transpile --write --path /absolute/path/to/MyGame

Language server from a local clone

@gmloop/lsp exposes GML code intelligence through a standard Language Server Protocol server that speaks JSON-RPC over stdio. The workspace builds the gmloop-lsp binary and is consumed by editor integrations and by lsp-mcp-server bridges — the language server is not wrapped by the gmloop CLI:

# build the LSP workspace and run its test suite once
pnpm --filter @gmloop/lsp run build:types
pnpm run test:lsp

# run the language server over stdio (launched by an editor or MCP bridge)
pnpm --filter @gmloop/lsp exec gmloop-lsp

For bridge configuration (.lsp-mcp.json, editor wiring) see docs/gml-lsp.md and src/lsp/README.md.

Architecture overview

WorkspacePathResponsibility
@gmloop/formatsrc/format/Formatter-only Prettier plugin surface
@gmloop/lintsrc/lint/ESLint v9 language plugin + lint rules
@gmloop/refactorsrc/refactor/Cross-file refactor planning/application
@gmloop/lspsrc/lsp/LSP language server bridge for editors and lsp-mcp-server
@gmloop/parsersrc/parser/GML parsing (ANTLR + AST construction)
@gmloop/semanticsrc/semantic/Project indexing, symbol resolution, and semantic analysis
@gmloop/transpilersrc/transpiler/GML -> JavaScript emission
@gmloop/runtime-wrappersrc/runtime-wrapper/HTML5 runtime hot-reload bridge
@gmloop/coresrc/core/Shared AST/types/helpers and static GameMaker language metadata
@gmloop/fixture-runnersrc/fixture-runner/Shared fixture discovery, execution, assertion, and profiling framework used by format/lint/refactor/integration suites
@gmloop/clisrc/cli/Unified command-line entrypoints
@gmloop/mcpsrc/mcp/MCP server surface for AI tooling integrations
@gmloop/uisrc/ui/Cross-project UI surfaces (graph, docs, fix, live-reload, playground)
@gmloop/agent-packsrc/agent-pack/Independently installable, vendor-neutral Auto-Game Agent Skills and project guidance

The Auto-Game agent pack is designed for standalone use in a game repository:

npm install -D @gmloop/agent-pack

Its published payload is ordinary Agent Skills directories plus portable project guidance, so consumers can inspect, copy, or point compatible tooling at the raw resources without installing the rest of GMLoop. When using the GMLoop UI, the Auto-Game page offers an initialize or update button whenever the opened project has no recorded pack installation or an older version.

The agent pack has no separate executable or postinstall mutation. The one universal command surface remains GMLoop's CLI:

gmloop agent-pack init --path path/to/Game.yyp

Agent Coordination Boundary

GMLoop is a first-class GameMaker companion surface for AI agents, not a general multi-agent coordinator. It owns GameMaker-specific project understanding, semantic graph context, parser/lint/refactor/format/fix workflows, live-reload status, MCP tool exposure, agent-pack installation, skill discovery, and project guidance.

GMLoop should complement, not replace, the official GameMaker CLI. In auto-game workflows, agents may use both GMLoop's MCP server and YoYoGames/gm-cli's ResourceTool MCP server directly. GMLoop owns GameMaker-specific semantic context, validation, lint/format/refactor workflows, hot reload, graph-backed inspection, task evidence, and missing high-level automation. It should avoid recreating official gm-cli project/resource/build/manual/publish capabilities unless GMLoop-specific context or behavior is required.

External agent coordinators such as Codex, Claude Code, Qwen, OpenHands, AutoGen, CrewAI, and LangGraph own model selection, agent scheduling, permissions, approvals, retries, memory, budgets, queues, task routing, and long-running workflow state.

External agent coordinator
        |
        | MCP + project files + skills + guidance
        v
GMLoop
  parser / semantic graph / lint / refactor / format / fix / live reload / UI / MCP
        |
        v
GameMaker project

The Auto-Game or Agents UI may present skills, packaged guidance, tool readiness, graph/search context, validation evidence, fix/refactor actions, and live-reload status. It may offer lightweight handoffs such as copying a prompt, opening an external agent, or launching a configured companion command. It must not become a multi-agent DAG editor, model router, arbitrary-framework prompt debugger, workflow engine, approval or permission system, memory store, or background task queue.

Agent-framework integrations are optional adapters over stable local contracts. The core product remains vendor-neutral and coordinator-neutral.

Everyday commands

# full validation (format check + lint + tests)
pnpm run check

# full test suite
pnpm test

# targeted suites
pnpm run test:format
pnpm run test:lint
pnpm run test:cli

# formatter
pnpm run format:gml -- /path/to/project

# parser AST inspection
pnpm run cli -- parse --path /path/to/project/scripts/demo.gml
pnpm run cli -- parse --write --path /path/to/project

# lint
pnpm run cli -- lint /path/to/project --write

# refactor
pnpm run cli -- refactor --old-name old_name --new-name newName

# refactor codemod (list configured codemods)
pnpm run cli -- refactor codemod --list

# fix (project-wide: refactor codemods + lint autofixes + format)
pnpm run cli -- fix --path /path/to/project
pnpm run cli -- fix --path /path/to/project --write

# graph index (build dual-root semantic graph index)
pnpm run cli -- graph index
pnpm run cli -- graph index --path /path/to/project --force

# graph search (query the graph index)
pnpm run cli -- graph search "player"
pnpm run cli -- graph search "player" --path /path/to/project

# graph doctor (validate graph index health)
pnpm run cli -- graph doctor --path /path/to/project

# transpile
pnpm run cli -- transpile --write --path /path/to/project

# hot-reload watch pipeline
pnpm run cli -- watch /path/to/project --verbose

# query the watch status server (--status-port and --status-host mirror watch's flags)
pnpm run cli -- live-reload status
pnpm run cli -- live-reload status --status-port 18000 --endpoint health

CLI wrapper environment knobs

These are the most commonly used CLI environment overrides.

VariablePurpose
PRETTIER_PLUGIN_GML_DEFAULT_ACTIONSet default CLI action when no command is provided (help or format).
PRETTIER_PLUGIN_GML_ON_PARSE_ERRORDefault parse error strategy for format (abort, skip, revert).
PRETTIER_PLUGIN_GML_LOG_LEVELDefault log level for formatter wrapper output.
PRETTIER_PLUGIN_GML_FORMAT_PATH / PRETTIER_PLUGIN_GML_FORMAT_PATHSOverride format entry-point resolution paths.
PRETTIER_PLUGIN_GML_IGNORED_FILE_SAMPLE_LIMITCap ignored-file samples in formatter summary output.
PRETTIER_PLUGIN_GML_SKIPPED_DIRECTORY_SAMPLE_LIMITCap skipped-directory samples in formatter summary output.
PRETTIER_PLUGIN_GML_UNSUPPORTED_EXTENSION_SAMPLE_LIMITCap unsupported-extension samples in formatter summary output.
WATCH_STATUS_HOST / WATCH_STATUS_PORTDefaults for live-reload status --status-host / live-reload status --status-port (mirrors watch --status-host / watch --status-port).

Use pnpm run cli -- <command> --help for full option details.

Configuration reference

Formatter configuration

The formatter is Prettier-based. Scope formatter config to .gml files.

{
  "overrides": [
    {
      "files": "*.gml",
      "options": {
        "parser": "gml-parse",
        "printWidth": 120,
        "tabWidth": 4,
        "semi": true,
        "allowInlineControlFlowBlocks": false,
        "logicalOperatorsStyle": "keywords"
      }
    }
  ]
}

Current formatter-specific options exposed by @gmloop/format:

  • allowInlineControlFlowBlocks — allow short, comment-free braced control-flow blocks (if, while, repeat, with) to stay on one line when the complete statement fits within printWidth; defaults to false
  • logicalOperatorsStyle ("keywords" or "symbols")

Lint configuration

Use the lint workspace presets in flat ESLint config:

import { Lint } from "@gmloop/lint";

export default [...Lint.configs.recommended];

Common composition:

import { Lint } from "@gmloop/lint";

export default [...Lint.configs.all];

Lint.configs.all enables every gml/* and feather/* rule at its recommended "warn" or "error" level. The narrower recommended, feather, and performance presets remain available for custom composition.

gmloop.json also supports lint preset selection for fixture/integration and project-config-driven lint flows via lintRuleset:

{
  "lintRuleset": "recommended",
  "lintRules": {
    "gml/no-globalvar": "error"
  }
}

Supported lintRuleset values are "all", "recommended", "feather", and "performance". lintRules remains optional and overrides rules from the selected ruleset when both are present.

See Workspace ownership boundaries for the current formatter/lint/refactor ownership contract.

Development

Setup

git submodule update --init --recursive
nvm use
pnpm install

Common scripts

# iterative local development
pnpm run build:ts
pnpm run lint:quiet
pnpm test

# pre-PR / CI-style validation
pnpm run lint:ci
pnpm run format:check
pnpm run report
pnpm run cli -- --help

Workspace shape

Each workspace follows:

  • package.json
  • index.ts
  • tsconfig.json
  • src/
  • test/

Generated artifacts live in dist/ and are disposable.

Documentation map

Start here for deeper context and plans:

References / Tools / Docs