Skip to content

phpClaw for PrestaShop

The PrestaShop adapter is a module. It adds back office pages under phpClaw, a CLI script, a REST endpoint with per-employee tokens, and 17 tools.


RequirementVersion
PHP8.1 or later
PrestaShop8.0 or later

Download phpClaw for PrestaShop (.zip)

In the back office, go to Modules → Module Manager → Upload a module and upload the ZIP. Then open phpClaw → Settings, choose a provider and enter the API key.

Need a specific version? Browse all releases →

phpClaw in a PrestaShop store

The Settings page shows when a newer version is available. The module declares PrestaShop 8.0.0 as its minimum and the running PrestaShop version as its maximum.


phpClaw → Settings stores its values in PrestaShop’s configuration: provider, model, API key, Base URL (for the Custom provider; https://, or http:// on localhost, 127.0.0.1 or ::1; the form saves any http:// URL, but the agent ignores one on any other host), system prompt, Store Messages (on by default), max iterations (1 to 50, default 20), Remote Skill URLs, and the phpClaw Cloud key, signing secret and disabled features. Cloud boots only while Store Messages is on.

With Store Messages off, the agent stores no message content. See Memory.

Seven more fields switch on the building blocks:

FieldNotes
Fallback ProviderOff by default; lists only providers with the same tool format as the provider, never Custom
Fallback Modelempty uses the fallback provider’s default
Fallback API Keyhidden when Fallback Provider is Off or Ollama
Rate Limit (requests/min)0 to 600, default 0 (off)
Response Cacheoff by default
Response Cache TTL (seconds)shown when Response Cache is on; 60 to 86400, default 3600
Max Token Budget0 to 10,000,000, default 0 (off)

The rate limit and the response cache are kept as files in PrestaShop’s cache directory.

Two fields set which tools the model is offered:

FieldNotes
Max Tools Per Turndefault 0, the automatic per-turn limit; -1 sends every tool; below -1 is saved as -1
Always Include Toolscomma-separated tool names offered on every turn, outside the limit; a name that is not a tool on the shop is skipped, and a denied tool stays denied

They apply to the CLI, the Chat page and the REST endpoint; the MCP server’s tool list does not use them.

The module’s config/phpclaw.php holds settings with no form field: workspace_root (default storage/phpclaw under the shop root), shell_allowlist (core’s default), tool_deny, guards, hooks, skills, events_bridge and update_server. Several can be set by defining a PHP constant before the module loads, such as PHPCLAW_SHELL_ALLOWLIST. shell_allowlist sets the commands a ShellTool added through the actionPhpclawExtraTools hook may run.


The module adds back office tabs. Their permissions, set under Advanced Parameters → Team → Permissions, decide who can use phpClaw:

GrantAllows
view on Chat (AdminPhpClawDebug)opening the Chat page, the REST endpoint, and every PrestaShop tool
edit on Chatsending messages from the Chat page
view on Settingsthe Settings page and Test Connection
edit on Settingssaving settings
SuperAdmin profileeverything above, seeing every employee’s conversations, issuing and revoking API tokens, and database

A fresh install grants these to the SuperAdmin profile and, when installed from the back office, to the profile of the employee who installed the module.

A tool call without the grant returns a FORBIDDEN error. A database call from an employee who is not a SuperAdmin fails with an error saying raw SQL needs a SuperAdmin. The CLI script skips both checks, except for database under mcp-server, which keeps them.


17 tools, plus core’s load_skill in chat, the REST endpoint and send, because core’s discovered skills, at least php_best_practices, are always registered. The Guide page and mcp-server list the 17:

GroupTools
PrestaShopps_product, ps_order, ps_customer, ps_category, ps_manufacturer, ps_cart, ps_stock, ps_coupon, ps_module, ps_report, ps_config, ps_employee, database, ps_log
Corecode_search, project_info, file_read

database runs one read-only SELECT, or with schema: true lists every table with its row count. It refuses the configuration, phpclaw_conversations and phpclaw_messages tables (for configuration the refusal points to ps_config), and SQL that names credential columns such as passwd, secure_key, api_key or salt. See Tools for the core tools.

ToolDoes
ps_productsearches and inspects products with stock and pricing
ps_ordersearches and inspects orders with status and payment data
ps_customersearches and inspects customers with order history statistics
ps_categorybrowses the category hierarchy
ps_manufacturersearches and inspects manufacturers and brands
ps_cartlists carts and finds abandoned ones
ps_stockchecks stock per product and finds items out of stock
ps_couponlists cart rules and vouchers
ps_modulesearches and inspects installed modules
ps_reportrevenue and order reports
ps_configreads configuration values
ps_employeesearches and inspects back office employees
databaseruns one read-only SELECT
ps_logreads the application log: the first of var/logs/dev.log, var/logs/prod.log, log/dev.log and log/prod.log that exists, else the newest dated dev-*.log or prod-*.log

ps_config never returns a configuration name that matches any of 17 credential patterns: asking for one returns no rows rather than an error, and meta.blocked_patterns lists the 17. Inside a structured value it withholds keys named like credentials, at any depth. Its default columns are name, value, id_shop and id_shop_group, because one name can hold a global row and a per-shop row. The stored value is returned only when the call passes name or include_values: true; otherwise value is replaced by value_type and value_size, and meta.values_included says which.

Every query response states what it cannot catch: a credential stored as plain text under a name that matches no pattern is returned in full. Most configuration rows are plain text, so do not treat the values as scrubbed.

shell_exec, http_request, file_write and file_edit are not registered: core marks them opt-in, and the module asks core only for its default tools. A module hooked to actionPhpclawExtraTools returns tools as objects or as class names. An object is used as it is. The class name \PhpClaw\Tools\ShellTool::class is built with shell_allowlist, and FileWriteTool::class and FileEditTool::class with workspace_root, both from config/phpclaw.php. Any other tool class whose constructor needs no argument is built with new, and anything else is dropped. A ShellTool a module builds with no allowlist uses core’s default, ls, pwd, df, wc, date, uptime, hostname and whoami, and the allowlist matches the first word of the command exactly, case included.

Tools added through the actionPhpclawExtraTools hook are placed before the built-in tools.

tool_deny in config/phpclaw.php removes tools by name or group:

GroupTools
group:commerceps_product, ps_order, ps_customer, ps_cart, ps_coupon
group:catalogps_category, ps_manufacturer, ps_stock
group:systemdatabase, ps_log, ps_config, ps_module, ps_employee, ps_report

Every agent is built with CliApprovalGate. In a terminal you are asked before a tool changes something; in the back office and the REST endpoint there is nobody to ask, so the change is refused. See Security: approval.

In the back office and the REST endpoint that refusal covers every file_write and file_edit call, and any shell_exec command on the allowlist but outside core’s read-only command list, so those complete only from the CLI script. A FileWriteTool added through actionPhpclawExtraTools by class name creates .php, .phtml and .phar files only under the send and chat commands; the mcp-server command builds its tools as non-interactive, so it refuses them. One a module builds itself does so only when constructed with allowPhpWrite: true.


Terminal window
# one-shot send
php modules/phpclaw/cli/phpclaw.php send "check stock levels for low inventory"
php modules/phpclaw/cli/phpclaw.php send "summarise orders" --stream --provider=openai --model=gpt-4o
php modules/phpclaw/cli/phpclaw.php send "and which of them are out of stock?" --continue --trace
php modules/phpclaw/cli/phpclaw.php send "and the rest?" --conv-id=<id>
# interactive chat
php modules/phpclaw/cli/phpclaw.php chat
php modules/phpclaw/cli/phpclaw.php chat --continue
php modules/phpclaw/cli/phpclaw.php chat --conv-id=<id>
php modules/phpclaw/cli/phpclaw.php mcp-server

send takes --stream, --provider, --model, --conv-id, --continue and --trace. chat opens an interactive session and takes --conv-id and --continue. mcp-server serves the tools over stdio; see MCP.

send prints the reply, then [provider:<p> model:<m> tokens:<n> iterations:<n> conversation:<id>] on stderr; with --stream it prints the reply, then [conversation:<id>]. --conv-id=<id> continues that stored conversation; an id with no stored conversation prints a warning and starts a new one. --continue picks the last conversation, whose id is kept in the PHPCLAW_CLI_LAST_CONV configuration key: one value per shop, so every shell user continues the same conversation, and uninstalling the module deletes it with the other PHPCLAW_ keys. The CLI reopens only the conversations it created; another employee’s id prints Conversation <id> is not available to the console and starts a new one. --trace prints one line per tool call on stderr, the tool name plus a short path or command, never the result.

chat keeps one conversation open, streams each reply and prints the tool calls as they run, then a line with the provider, model, input and output tokens, the tools that ran and the conversation id. It needs a terminal: with piped input it refuses and exits 1. A line starting with / is a command and is never sent to the agent:

CommandWhat it does
/helpList these commands
/toolsList the active tools
/model <name>Switch the model for this session only
/provider <slug>Switch the provider for this session only
/newStart a new conversation
/convPrint the conversation id
/quietTurn the tool trace off or on
/clearClear the screen
/exitLeave; Ctrl+D also leaves

While the agent works, a Thinking... spinner shows until the first word of the reply arrives. It is not shown when the output is not a terminal, and without the pcntl extension a still Thinking... line is printed instead of the animation. A failed turn prints one line without the exception text and the session goes on; the exception goes to the PHP error log, which is the terminal’s stderr when PHP has no error_log set. On leaving it prints the command to resume. /model and /provider never write the module settings; a provider that cannot be built is named and the session keeps the current one.

From PHP, phpclaw_agent('message') returns the reply text. For the full response, use the agent:

use PhpClaw\PrestaShop\Plugin;
$response = Plugin::getInstance()->engine()->send('Analyse cart abandonment this week.');
echo $response->text;

Both use the module’s singleton, which gets its database and employee when a back office page or the CLI script boots it. Called before that in the same request, it is built with no database, and database fails with “no database connection available”.


One front controller, with the action in the query string:

ActionURLReturns
send{shop}/index.php?fc=module&module=phpclaw&controller=api&action=sendthe reply as JSON
chat/stream{shop}/index.php?fc=module&module=phpclaw&controller=api&action=chat/streamServer-Sent Events

Both need POST, with message (at most 50,000 bytes) and an optional conversation_id, as a JSON body or as form fields.

Terminal window
curl -X POST "https://example.com/index.php?fc=module&module=phpclaw&controller=api&action=send" \
-H "Authorization: Bearer <token>" \
-H "Content-Type: application/json" \
-d '{"message":"how many orders came in today?"}'
  • Bearer token. A SuperAdmin issues a token for an employee on phpClaw → Settings. It is shown once and stored as a SHA-256 hash. It acts as that employee, who must be active and hold view on the Chat tab. Only the Authorization header is read. The employee and the grant are checked on every request, so revoking the token, removing the grant or deactivating the employee takes effect immediately.
  • Back office session. A logged-in employee with view on the Chat tab, from a same-origin request.
StatusCodeWhen
400phpclaw_empty_message, phpclaw_long_messagethe message is missing or too long
403phpclaw_forbiddennot authenticated, no Chat grant, or another employee’s conversation
404phpclaw_not_foundunknown action
405phpclaw_forbiddennot a POST
422phpclaw_guarda guard blocked the message
422phpclaw_budget_exceededthe token budget was reached: “Token budget reached for this run.”
429phpclaw_rate_limitedmore than 60 requests from one IP in a 60-second window (“Too many requests. Please slow down.”), or the Rate Limit setting’s wait ran out (“Rate limit reached, try again shortly.”)
500phpclaw_erroranything else failed
503phpclaw_not_configuredno provider or model is configured, or the agent raised a configuration error

chat/stream reports guard and agent errors as an error event inside a 200 response. A spent token budget or the Rate Limit setting sends its message as the error event, with status 422 or 429 when the response has not started yet.

The rate limit counts in APCu. Without APCu nothing is counted, so no request is limited.


PageTab permissionShows
SettingsSettingsthe settings, Test Connection, and API tokens for SuperAdmins
ChatChatthe chat interface with the employee’s conversations
AnalyticsAnalyticsconversation and message counts; store-wide for SuperAdmins, otherwise the employee’s own
GuideGuidethe registered tools
AboutAboutmodule information

Each conversation stores the creating employee’s id in id_employee, from the back office session or the token’s employee. Conversations created from the CLI store 0. An employee sees and opens only their own conversations; opening another’s is refused with 403. SuperAdmins see every conversation.

The agent always uses the ps_router memory driver, PsRouterMemory: conversations in the conversation tables, everything else in phpclaw_memory. The module also registers ps_db (PsDbMemory, phpclaw_memory only) and ps_setting (PsSettingMemory, PrestaShop’s configuration table).


A module registers additions by hooking these actions and returning an array of entries; phpClaw merges every module’s returned array after the hook runs. The bucket parameter is always an empty array, so changing it adds nothing:

HookAdds
actionPhpclawExtraToolstools
actionPhpclawExtraGuardsguards
actionPhpclawExtraHookslifecycle listeners
actionPhpclawExtraSkillsskills
actionPhpclawExtraMemorymemory drivers
actionPhpclawExtraProvidersproviders

While events_bridge is on, every lifecycle event is also executed as a PrestaShop hook named actionPhpClaw followed by the event name with each dot-separated part capitalised and the dots removed, such as actionPhpClawAgentAfter. Underscores are kept: agent.max_iterations becomes actionPhpClawAgentMax_iterations. The hook gets event and context parameters. The event names are listed on the Hooks page.