Skip to content

Town plan reference

This page is generated from the JSON Schema of the town plan, https://myrtille.eu/schemas/town-plan/v1.json, itself generated from the schema the town hall validates the file with. The town plan page explains the file with an example.

A field marked yes under “Required” must be present when its parent is. An unknown key is an error everywhere, except under meta. A list such as couriers[] repeats the fields below it for each item.

Required. number 1. Version of the town plan format: 1.

Required. object. The town itself.

Field Type Required Default Description
town.id string, 1 to 60 characters, pattern ^[a-z0-9][a-z0-9-]*$ yes Stable id of the town. Once the first account exists, it must be the id of that town.
town.name string, 1 to 120 characters yes Name of the town.
town.locale one of en, fr no en Language of the reports of the town.
town.timezone string, 1 to 60 characters no UTC Time zone of the reports of the town, for example Europe/Paris.

Required. list of objects, 1 to 50 items. The sources of the town, at least one. Their credentials never appear in this file.

Field Type Required Default Description
couriers[].id string, 1 to 60 characters, pattern ^[a-z0-9][a-z0-9-]*$ yes Stable id of the courier, named by the districts and buildings it feeds. Ids starting with agent- belong to the enrolled agents.
couriers[].type one of coolify, claude-code, webhook, docker, git-github, mcp, dokploy, otel, mock yes The kind of source this courier reads.
couriers[].instance string, 1 to 60 characters, pattern ^[a-z0-9][a-z0-9-]*$ no Name of the source instance, the courier id when absent. Its address and tokens live encrypted in the town hall, never in this file.
couriers[].discover boolean no true Whether the resources the source reports are added to the town. With false, a citizen it reports joins the town only when citizens lists it by its id; a citizen already in the town stays.
couriers[].poll object no Polling cadence of a Coolify courier.
couriers[].poll.idleSeconds integer, 10 to 3600 no 45 Seconds between two polls while nothing runs.
couriers[].poll.activeSeconds integer, 1 to 60 no 3 Seconds between two polls while a deployment runs, and for a minute after an action.
couriers[].agents list of strings, at most 100 items, each 1 to 60 characters, pattern ^[a-z0-9][a-z0-9-]*$ no Names of the enrolled agents this courier reads. On a coolify courier, the Docker agents deployed on its servers: they may report the crashes and stream the logs of its citizens.
couriers[].mcp object no The MCP server of a courier of type mcp: its citizen and the tools the town may call.
couriers[].mcp.transport one of http, stdio no http http: the town hall calls the streamable HTTP endpoint stored for this courier. stdio: a local agent runs the server.
couriers[].mcp.agent string, 1 to 60 characters, pattern ^[a-z0-9][a-z0-9-]*$ no stdio only: name of the enrolled local agent that runs the server.
couriers[].mcp.server string, 1 to 60 characters, pattern ^[a-z0-9][a-z0-9-]*$ no stdio only: name of the server in the configuration of that agent, the courier id when absent.
couriers[].mcp.name string, 1 to 120 characters no Name of the citizen shown in the town, the courier id when absent.
couriers[].mcp.district string, 1 to 60 characters, pattern ^[a-z0-9][a-z0-9-]*$ yes Id of the district the citizen of the server lives in.
couriers[].mcp.building string, 1 to 60 characters, pattern ^[a-z0-9][a-z0-9-]*$ no Id of the building the citizen of the server belongs to.
couriers[].mcp.timeoutSeconds integer, 1 to 120 no 30 Seconds the town hall waits for one answer of the server.
couriers[].mcp.tools list of objects, at most 50 items no [] The tools the town may call. A tool not listed here is never offered nor called.
couriers[].mcp.tools[].name string, 1 to 111 characters, pattern ^[A-Za-z0-9_-]+(\.[A-Za-z0-9_-]+)*$ yes Name of the tool exactly as the MCP server lists it. It becomes the action mcp.tool.<name in lowercase>.
couriers[].mcp.tools[].danger one of safe, destructive no destructive destructive (the default) always asks for a confirmation; safe follows the confirmation policy of the district.
couriers[].mcp.tools[].minRole one of operator, admin no admin The lowest role allowed to call the tool: admin (the default) or operator.
couriers[].repositories list of objects, at most 200 items no Repositories of a git-github courier: pull requests become temporary citizens of the previews district.
couriers[].repositories[].name string, pattern ^[A-Za-z0-9](?:[A-Za-z0-9-]{0,38})\/[A-Za-z0-9._-]{1,100}$ yes
couriers[].repositories[].district string, 1 to 60 characters, pattern ^[a-z0-9][a-z0-9-]*$ no
couriers[].repositories[].building string, 1 to 60 characters, pattern ^[a-z0-9][a-z0-9-]*$ no
couriers[].repositories[].preview object no
couriers[].repositories[].preview.courier string, 1 to 60 characters, pattern ^[a-z0-9][a-z0-9-]*$ yes
couriers[].repositories[].preview.application string, pattern ^[A-Za-z0-9_-]{1,64}$ yes
couriers[].district string, 1 to 60 characters, pattern ^[a-z0-9][a-z0-9-]*$ no District where an otel courier puts the services it discovers by their service.name. Default: the first district whose source is this courier.
couriers[].meta object of free keys no Free keys of your own, never a secret: a key that looks like one is refused.

Required. list of objects, 1 to 50 items. The districts of the town, at least one: one per environment, plus previews and local ones.

Field Type Required Default Description
districts[].id string, 1 to 60 characters, pattern ^[a-z0-9][a-z0-9-]*$ yes Stable id of the district.
districts[].name string, 1 to 120 characters yes Name shown in the town.
districts[].kind one of environment, previews, local yes environment for an environment of a source, previews for preview deployments, local for developer workstations.
districts[].source object no Where the citizens of the district come from.
districts[].source.courier string, 1 to 60 characters, pattern ^[a-z0-9][a-z0-9-]*$ yes Id of the courier the district mirrors.
districts[].source.environment string, 1 to 120 characters no Name of the environment in the source, for example production.
districts[].source.previews boolean no True when this district holds the preview deployments of the courier.
districts[].confirmation one of always, destructive, never no Which actions ask for a confirmation: always, destructive, or never (refused for a production district). Turning actions on is never done here: an admin does it in the town.
districts[].overlay object no Local overlay of a local district.
districts[].overlay.shadows string, 1 to 60 characters, pattern ^[a-z0-9][a-z0-9-]*$ yes Id of the district whose twin services a running local service greys out.
districts[].position object no Fixed place of the district, in tiles, with rendering.layout manual.
districts[].position.x integer, at least 0 yes Column, in tiles.
districts[].position.y integer, at least 0 yes Row, in tiles.
districts[].meta object of free keys no Free keys of your own, never a secret: a key that looks like one is refused.

Optional. list of objects, at most 200 items. The buildings of the town: one per project of a source, or groups made by hand.

Field Type Required Default Description
buildings[].id string, 1 to 60 characters, pattern ^[a-z0-9][a-z0-9-]*$ yes Stable id of the building.
buildings[].name string, 1 to 120 characters yes Name shown in the town.
buildings[].source object no The project of a source this building stands for. Without it, the building only groups citizens.
buildings[].source.courier string, 1 to 60 characters, pattern ^[a-z0-9][a-z0-9-]*$ yes Id of the courier the building mirrors.
buildings[].source.project string, 1 to 200 characters yes Name of the project in the source.
buildings[].position object no Fixed place of the building, in tiles, with rendering.layout manual.
buildings[].position.x integer, at least 0 yes Column, in tiles.
buildings[].position.y integer, at least 0 yes Row, in tiles.
buildings[].meta object of free keys no Free keys of your own, never a secret: a key that looks like one is refused.

Optional. list of objects, at most 800 items. Overrides of discovered citizens, by id, and citizens declared by hand. Discovered citizens need not be listed.

Field Type Required Default Description
citizens[].id string, 3 to 300 characters, pattern ^[a-z0-9][a-z0-9-]*:[^\s:]\S*$ yes Id of the citizen: <courier>:<kind>:<ref>. A discovered citizen is overridden by its exact id.
citizens[].name string, 1 to 120 characters no Name shown in the town.
citizens[].kind one of service, database, automation, agent, mcp, server, preview, local no The kind of citizen.
citizens[].avatar string, at most 60 characters no The look of the citizen.
citizens[].building string, 1 to 60 characters, pattern ^[a-z0-9][a-z0-9-]*$ no Id of the building the citizen belongs to.
citizens[].district string, 1 to 60 characters, pattern ^[a-z0-9][a-z0-9-]*$ no Id of the district the citizen belongs to.
citizens[].expectedEvery string, pattern ^\d+(s|m|h|d)$ no How often the citizen gives news, such as 90s, 10m, 6h or 1d. Past it, the citizen turns unknown.
citizens[].actions list of objects, at most 20 items no Outgoing actions of a citizen declared by hand.
citizens[].actions[].type string task.run yes The kind of action: task.run.
citizens[].actions[].label string, 1 to 80 characters yes Label of the action in the town.
citizens[].actions[].webhook string, at most 2048 characters, format uri yes https address the town hall calls, with a signed request, to run the action.
citizens[].repo object no The repository of an agent citizen.
citizens[].repo.path string, 1 to 500 characters yes Path of the repository on the workstation, which places the Claude Code sessions run there.
citizens[].repo.agent string, 1 to 60 characters, pattern ^[a-z0-9][a-z0-9-]*$ yes Name of the local agent of that workstation.
citizens[].repo.localPorts list of integers, at most 20 items, each 1 to 65535 no Ports the local agent watches on that workstation for the local overlay.
citizens[].missions object no Missions of an agent citizen.
citizens[].missions.enabled boolean no false Whether members may give this agent a mission.
citizens[].missions.maxConcurrent integer, 1 to 1 no 1 Missions at once in this repository: 1.
citizens[].missions.branchPrefix string, at most 60 characters no mission/ Prefix of the branch each mission creates.
citizens[].position object no Fixed place of the citizen, in tiles, with rendering.layout manual.
citizens[].position.x integer, at least 0 yes Column, in tiles.
citizens[].position.y integer, at least 0 yes Row, in tiles.
citizens[].meta object of free keys no Free keys of your own, never a secret: a key that looks like one is refused.

Optional. object. Settings of the mail.

Field Type Required Default Description
mail.quietHours object no Hours when the notifications of the mail wait: the push of an item of another urgency than except is sent when they end, if the item is still open, and the daily summary waits too. The mail shows every item at once.
mail.quietHours.from string, pattern ^([01]\d|2[0-3]):[0-5]\d$ yes Start of the quiet hours, HH:MM in the time zone of the town, included.
mail.quietHours.to string, pattern ^([01]\d|2[0-3]):[0-5]\d$ yes End of the quiet hours, HH:MM in the time zone of the town, excluded. Earlier than from, they span midnight; equal to from, there are none.
mail.quietHours.except list of values among low, normal, high, critical no ["critical"] Urgencies that still notify during the quiet hours. critical always does, listed or not.
mail.defaults object no Default lifetimes of the mail.
mail.defaults.incidentTtlHours integer, 1 to 720 no 24 Hours an incident with a fixed lifetime stays open before it expires: failed deployments, container, backup and task incidents. Without this block, 24 h, and 48 h for backups and tasks. An incident that ends on an event (server unreachable, courier disconnected) waits for it.

Optional. object. How the town is drawn.

Field Type Required Default Description
rendering.layout one of auto, manual no auto auto lays the town out by itself; manual keeps the positions given in this file.
rendering.tileset string, at most 60 characters no default Name of the tileset the town is drawn with. The town ships default only: another name is drawn with default, and the town hall logs a warning.
rendering.palette string, at most 60 characters no endesga32 Name of the palette of the art. The town ships endesga32 only (a fixed palette): another name is drawn with endesga32, and the town hall logs a warning.
rendering.decor list of objects, at most 200 items no Decorations of buildings, drawn on the back wall of each copy of the building, ten props at most.
rendering.decor[].building string, 1 to 60 characters, pattern ^[a-z0-9][a-z0-9-]*$ yes Id of the building to decorate.
rendering.decor[].props list of strings, at most 50 items, each at most 60 characters yes Props to place, in order: a tile of the furniture (plant-1, poster-2, coffee-machine, shelf, lamp), or a family and any name after it (plant, poster-travel), which always gives the same tile for the same name. A prop the town has no tile for is left out, and the town hall logs a warning.

Optional. object of free keys. Free keys of your own, never a secret: a key that looks like one is refused.