Learn

For AI agents

How an agent works in a Nimbly project: where to read, where each block lives and which rules always hold.

This page is for an AI agent that writes code in a Nimbly project, and for the people who work with one. A Nimbly app is made of small blocks in predictable places, so a task usually touches a few short files.

Read first

Every project has the full reference in NIMBLY.md at its root. Do not read it in one go. Look up what the task needs:

./nimbly docs:list
./nimbly docs:search "router_accept"
./nimbly docs:section "Template Syntax > route.inc"
  • docs:list prints every heading, to find the right term.
  • docs:search finds one term in the text.
  • docs:section prints one section by its heading path.

The same content is on this site as plain text. /llms.txt lists every page, /llms-full.txt holds all pages in one file, and every page has a Markdown version at its own address with .md added, for example /en/docs/concepts/resources.md. /nimbly.json lists the stack, the included features and the CLI commands.

Where each block lives

Block Place What it holds
Route ext/uri/<path>/index.tpl One address. The folder path is the URL.
Template ext/tpl/<name>/index.tpl A reusable block of markup, called as [#name#].
Resource ext/data/<resource>/.meta The fields, validation, indexes and permissions of one kind of record.
Library ext/lib/<name>.php PHP logic, called as [#name#]. No markup.
Module ext/modules/<name>/ A feature with its own routes and data.

The framework is in core/ and is the same for every project. Application work goes in ext/.

Rules that always hold

  • Inspect the existing code before adding something new. Reuse a block that is already there.
  • Markup belongs in templates. PHP libraries prepare data and do not print HTML.
  • [#if#] is one tag. It has no block form. Conditional markup goes in its own template, named with tpl=.
  • [#set#] does not replace a value that is already set, unless overwrite is given.
  • A static route has no route.inc. A dynamic route checks its input and answers with router_accept() or router_deny().
  • PHP uses snake_case for functions, variables and file names.
  • Use the existing roles and permissions. Do not build a second permission system.

Check your work

./nimbly build
./nimbly test:architecture --strict
./nimbly test:run

Run the smallest check that covers the change. Content and data are files in the repository, so every change can be reviewed as a diff before it is committed.

View this page as Markdown