El docs/ de este repo era el set antiguo sin numerar: copy_scaffold lo omite desde 2026-06-11 y copia la canónica de agenticSystem/docs en cada web, así que ningún cambio aquí llegaba a nadie (los PRs #1 y #3 lo editaban). Se sustituye por un README que señala la fuente. CLAUDE.md apuntaba a esos 12 nombres, que no existen en ninguna web: ahora enlaza a los 13 canónicos numerados. Nota de hooks por HTTP (404 a propósito sin X-Hooks-Token → call_hook).
10 KiB
Acai CMS — Project Instructions
This is an Acai CMS website project. Follow these instructions when working with the codebase.
Environment
- The site runs on Acai Forge — get the live editable URL with the
get_web_urlMCP tool (never assume a fixed domain) - You can make HTTP requests to test pages, APIs, or form submissions against that URL
- If you need to inspect the live site, use browser tools (Playwright MCP) or HTTP requests to the Forge URL
Project Structure
.
├── template/estandar/
│ ├── modulos/ # Builder modules (visual components)
│ │ └── <module-id>/
│ │ ├── index-base.tpl # Twig template (source — EDIT THIS)
│ │ ├── style.css # Module styles
│ │ └── script.js # Module JavaScript
│ │ ├── index.tpl # Compiled (auto-generated, do NOT edit)
│ │ ├── index-twig.tpl # Compiled (auto-generated, do NOT edit)
│ │ └── builder.json # Compiled builder vars (auto-generated, do NOT edit)
│ ├── css/ # Global CSS
│ └── js/ # Global JavaScript
├── hooks/ # PHP hooks (server-side logic)
├── cms/
│ ├── data/schema/ # Database table schemas (JSON)
│ ├── lib/plugins/ # CMS plugins
│ └── uploads/ # Uploaded media files
└── .acai # Project config (domain, tokens, DB credentials)
Key Concepts
Modules (template/estandar/modulos/)
Visual components that the site builder uses. Each module is a self-contained unit with its own template (Twig + Acai attributes), CSS, and JS. Modules are placed on pages via the drag-and-drop builder. The editable file is always index-base.tpl.
- Include other modules:
<module_id :param1="value1"></module_id> - Each module instance gets a unique
section_idvariable for anchors/scoping - Use
internovariable to detect CMS editor mode vs public view
See docs/03-modules-and-sections.md for detailed rules.
Pages
Every record with an enlace field is a page. Pages are either Builder (modular) or Standard:
- Builder:
controlador=cms/lib/plugins/builder_saas/controlador.php— content via modules - Standard:
controlador=cms/lib/plugins/builder_saas/controlador_tabla.php— content in record fields
Critical: Never change enlace or controlador of existing pages unless explicitly asked.
See docs/04-pages-and-records.md for full details.
General Sections
Database-backed templates (headers, footers, record views) that use the thisrecord variable to access record fields. They use the same Twig + Acai attribute engine as modules.
- Upload fields return arrays:
thisrecord.image[0].urlPath - Foreign keys use
_numsuffix:category_num
See docs/03-modules-and-sections.md for details.
Hooks (hooks/)
PHP files that execute server-side logic. Triggered by:
- Twig filter:
'hooks/module_id/' | hook({param: value}) - HTML tag:
<hook result="var" endpoint="/hooks/module_id/" :param="value"></hook> - JavaScript:
CmsApi.hook('/hooks/module_id/', {param: value}, callback) - Form action: via
c-formattribute
There are two valid hook locations:
- Global hooks in
hooks/hooks.<hook-id>.phpfor reusable/shared server-side logic - Module-specific hooks in
template/estandar/modulos/<module-id>/hook.phpfor logic owned by a single module
How to reference them:
- Global hook
hooks/hooks.calcular_precio.php-> endpoint/hooks/calcular_precio/ - Module hook
template/estandar/modulos/hero_banner/hook.php-> endpoint/hooks/hero_banner/ - Module hook
template/estandar/modulos/buscadorapartados_hjd8s/hook.php-> endpoint/hooks/buscadorapartados_hjd8s/
Rule of thumb:
- If the logic is only used by one module, prefer that module's
hook.php - If the logic will be reused by several modules/pages, create a global hook in
hooks/ - Return arrays from hooks; do not use
echo json_encode(...)orexit - Calling a hook over plain HTTP (
curl https://<forge-url>/hooks/x/) returns 404 on purpose: the endpoint requires theX-Hooks-Tokenheader. From the agent use thecall_hookMCP tool; the site's own JS (CmsApi.hook) already sends the token
See docs/06-hooks-and-cmsapi.md for usage.
Acai Core (web-base)
The project workspace contains only the customization layer (modules, hooks, schemas, uploads). The CMS core (routing, rendering engine, admin panel, APIs) lives in a separate, shared directory called web-base.
Do NOT modify web-base files — they are shared across all projects.
Critical Rules
- Before working with any area (hooks, modules, templates, CSS/JS, etc.), read the corresponding documentation in
docs/first. Do not guess or assume — always consult the docs before taking action. - NEVER use
mkdirto create directories. Instead, useacai-writeto create the first file inside the directory — this creates parent directories automatically. For example, to create a new module, directly write theindex-base.tplfile. - Only edit
index-base.tplin modules —index.tpl,index-twig.tpl, andbuilder.jsonare auto-generated - Editing or creating any
index-base.tplthroughacai-writeoracai-line-replacetriggers automatic compilation.compile_moduleis only for manual recovery when you need to force a recompile without changing the file. script.jsandstyle.cssare static files — do NOT use Twig syntax inside them. Pass dynamic values fromindex-base.tplviadata-*attributes.- Use Twig filters (with
|), never Twig functions - Table names without
cms_prefix everywhere - Primary key is
num, neverid - Upload fields are arrays — access with
[0].urlPath - Tailwind CSS as primary styling, custom CSS scoped with BEM when needed
- Twig concatenation uses
~operator:'value=' ~ variable enlace(link) fields already include slashes — NEVER modify an existing enlace unless explicitly asked- NEVER modify the
controladorfield of existing records — it defines whether a page is Builder or Standard - This repository is PUBLIC. NEVER commit secrets (API keys,
ANTHROPIC_*tokens, passwords). Local Claude Code config with credentials goes in.claude/settings.local.json(git-ignored), never in.claude/settings.json. Enable the secret-scanning hook once per clone:git config core.hooksPath .githooks. A leaked key stays in git history even after deleting it: rotate it immediately.
MCP Tools
This project has MCP tools for managing modules, records, media, and more. Before starting any task, consult the tools reference for the correct workflow.
See docs/09-mcp-tools-reference.md for the complete list of available tools and step-by-step workflows, and docs/11a-decision-table.md to route a request to the right tool.
Key workflows:
- Create module: Read docs/03-modules-and-sections.md first → create files with
acai-write/ refine withacai-line-replace→ automatic compile onindex-base.tpl→add_module_to_record(returns sectionId) →set_module_config_vars(returns uploadFields) → images via uploadFields. Usecompile_moduleonly if you need a manual recompile without editing the file. - Edit module:
acai-view→acai-line-replace(oracai-writefor full rewrites) → automatic compile onindex-base.tpl - Add images: use
uploadFieldsfromset_module_config_varsresponse →upload_record_image - Generate images:
generate_image→upload_record_imagewith returned URL
Documentation
The docs/ folder holds the 13 canonical Acai docs (numbered; the same set the Forge agent uses). They are refreshed automatically from the canonical source — do not edit them here.
- docs/01-builder-fields.md — Builder field types (
data-field-*), tabs, conditional visibility, colors/colorpicker, components - docs/02-twig.md — Twig filters reference (get, hook, queryDB, translate, module, set…) and
{% if %}vsc-if - docs/03-modules-and-sections.md — Modules,
index-base.tpl, general sections (custom-{table}), module creation workflow, uploads - docs/04-pages-and-records.md — Page types (Builder vs Standard), controller,
enlace, records withnum, visibility, critical rules - docs/05-tables-and-fields.md — Creating and changing tables and fields with the MCP tools,
regenerate_enlaces - docs/06-hooks-and-cmsapi.md — PHP hooks (global and per module),
CmsApi/CocoDB, middleware,X-Hooks-Token/call_hook, record creation - docs/07-css-js-conventions.md — Tailwind, BEM scoped CSS,
data-*for dynamic values,CmsApi.hookfrom JS, Vue 3, native components - docs/08-layout-and-libraries.md — Header/footer/global CSS/global JS via
get_layout_field/set_layout_field, global libraries - docs/09-mcp-tools-reference.md — Full MCP tools inventory by category and canonical workflows
- docs/10-production-patterns.md — Real production snippets (header with menu, FAQ, zigzag, forms, listings, structured data)
- docs/11a-decision-table.md — "User intent → MCP tool" routing table
- docs/11b-rules-cheat-sheet.md — Non-negotiable rules cheat sheet (
cms_,num,_num, upload arrays,c-if), field types - docs/12-glossary.md — Short definitions of Acai terms (sectionId, recordNum, apartados, builder_custom, enlace, controlador…)