# Write game scripts with an agent

> An AI agent writes DiceyTable game scripts with script_write. It saves through the Script editor and gets back compile errors and scanner findings to fix.

- Question: How does an agent write and check my game's scripts?
- Source: https://diceytable.com/docs/ai-agents/workflows/write-scripts
- Last verified: 2026-10-09

An agent writes a script with `script_write`. The tool saves the source through the Script editor's own save button,
then returns two lists: compile errors and the safety scanner's findings. The agent fixes every item on both lists
before it moves on.

Scripts are how a game enforces its own rules: dealing at the start, checking moves, keeping score. The
[tabletop game scripting](https://diceytable.com/features/tabletop-game-scripting) page shows what that looks like for players.

## What you'll need

- An editor tab [paired with your agent](https://diceytable.com/docs/ai-agents/setup/pairing), holding the project lease. The lease is the
  editor's lock that lets one tab at a time change a project.
- A key with **Edit projects**.
- A game project. Room and table packs don't run scripts, so `script_write` refuses to create one there.

## Which kind of script should the agent write?

DiceyTable has two script surfaces, and they don't mix:

- **Table scripts** are TypeScript. They use `world`, `globalEvents` and `refObject`, and most games want these.
- **Mod scripts** are JavaScript. They use the `api` object, and each feature they use must be allowed in the manifest.

[Choosing a surface](https://diceytable.com/docs/scripting/concepts/choosing-a-surface) helps you pick. Point your agent at the
[Scripting API](https://diceytable.com/docs/scripting-api) too, so it writes against the real functions.

## Step 1: Read what's there

`script_list` lists the project's scripts and the entities each one is attached to. `script_read` reads one. A quick
read stops the agent from writing a second script that does the same job.

## Step 2: Write the script

To create a table script, the agent calls `script_write` with a name and the source, and no `scriptId`. To change
one, it passes the `scriptId` from `script_list`.

The mod's entry script has an id that starts with `file:`, such as `file:scripts/main.js`. It's the only file script
that `script_write` will touch. Other text files go through `asset_write_text`.

`script_write` is the only way an agent can write a script. It types the source into the Script editor and runs the
editor's save. So the agent's script gets the same compiler and the same scanner as yours.

> **Good to know.** If you have unsaved changes in that script's tab, `script_write` stops with `focused-by-user`. It
> won't type over your work. Save or close the tab, then ask again.

## Step 3: Fix every finding

The result lists compile errors from the TypeScript checker and issues from the **safety scanner**. The scanner is
the check that keeps scripts away from the browser. It runs again before every preview and when the mod is registered. A script
it rejects won't run anywhere, so the agent should treat every finding as a blocker.

## Why did the scanner reject a comment?

The scanner reads a script as plain text and matches whole words. It doesn't know what is code and what is a comment.
So it rejects these words anywhere in a script, even in a comment or a string:

- `window`, `document`, `parent`, `top` and `opener`
- `fetch`, `XMLHttpRequest`, `WebSocket` and `EventSource`
- `localStorage`, `sessionStorage`, `indexedDB` and `cookie`
- `eval`, `Function` and `importScripts`
- `setInterval` and `requestAnimationFrame`

A comment like "move the top card" fails because of `top`. Reword it as "move the first card". For table scripts the
scanner reads the compiled code, and comments survive into it. [Script safety](https://diceytable.com/docs/mods/scanner/script-safety) has
the full rules.

## Step 4: Attach and add a HUD

`script_attach` attaches a table script to an entity and can set its script variables. The mod's entry script runs
for the whole table, so it can't be attached.

A game that talks to players off the table also needs a **game UI layout**, the panels and buttons of its HUD.
`ui_layout_set` saves a layout to the project's library, and `ui_layout_attach` adds it to the scene. See
[Game UI (HUD)](https://diceytable.com/docs/scripting/concepts/game-ui) for what a layout can hold.

## Step 5: Test it

A script that compiles can still have bugs. The agent saves, runs `project_validate`, then
[play-tests in a preview](https://diceytable.com/docs/ai-agents/workflows/playtest). `diagnostics_watch` waits for a script error that only
shows up later, such as after a card is dropped. [Find errors with the diagnostics hub](https://diceytable.com/docs/ai-agents/workflows/diagnostics)
shows how to read them.

## What stays the same

The agent writes source text and nothing more. It never runs code inside a mod's sandbox, and a mod still has no
network. Turning on the `read-hidden-information` or `plugin-call` capabilities always waits for your click in the
tab. [AI agent safety](https://diceytable.com/docs/ai-agents/concepts/security-model) explains the rest.

## Next steps

- [Play-test your game with an agent](https://diceytable.com/docs/ai-agents/workflows/playtest): prove the rules work.
- [Instructions to give your AI agent](https://diceytable.com/docs/ai-agents/workflows/agent-instructions): bake the scanner rules into
  every session.
- [Build a game with an AI agent](https://diceytable.com/docs/ai-agents/workflows/build-a-game): where scripts fit in the whole loop.
