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.
Install
Section titled “Install”| Requirement | Version |
|---|---|
| PHP | 8.1 or later |
| PrestaShop | 8.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 →

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.
Settings
Section titled “Settings”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:
| Field | Notes |
|---|---|
| Fallback Provider | Off by default; lists only providers with the same tool format as the provider, never Custom |
| Fallback Model | empty uses the fallback provider’s default |
| Fallback API Key | hidden when Fallback Provider is Off or Ollama |
| Rate Limit (requests/min) | 0 to 600, default 0 (off) |
| Response Cache | off by default |
| Response Cache TTL (seconds) | shown when Response Cache is on; 60 to 86400, default 3600 |
| Max Token Budget | 0 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:
| Field | Notes |
|---|---|
| Max Tools Per Turn | default 0, the automatic per-turn limit; -1 sends every tool; below -1 is saved as -1 |
| Always Include Tools | comma-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.
Permissions
Section titled “Permissions”The module adds back office tabs. Their permissions, set under Advanced Parameters → Team → Permissions, decide who can use phpClaw:
| Grant | Allows |
|---|---|
view on Chat (AdminPhpClawDebug) | opening the Chat page, the REST endpoint, and every PrestaShop tool |
edit on Chat | sending messages from the Chat page |
view on Settings | the Settings page and Test Connection |
edit on Settings | saving settings |
| SuperAdmin profile | everything 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:
| Group | Tools |
|---|---|
| PrestaShop | ps_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 |
| Core | code_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.
| Tool | Does |
|---|---|
ps_product | searches and inspects products with stock and pricing |
ps_order | searches and inspects orders with status and payment data |
ps_customer | searches and inspects customers with order history statistics |
ps_category | browses the category hierarchy |
ps_manufacturer | searches and inspects manufacturers and brands |
ps_cart | lists carts and finds abandoned ones |
ps_stock | checks stock per product and finds items out of stock |
ps_coupon | lists cart rules and vouchers |
ps_module | searches and inspects installed modules |
ps_report | revenue and order reports |
ps_config | reads configuration values |
ps_employee | searches and inspects back office employees |
database | runs one read-only SELECT |
ps_log | reads 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 |
What ps_config returns
Section titled “What ps_config returns”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.
Denying tools
Section titled “Denying tools”tool_deny in config/phpclaw.php removes tools by name or group:
| Group | Tools |
|---|---|
group:commerce | ps_product, ps_order, ps_customer, ps_cart, ps_coupon |
group:catalog | ps_category, ps_manufacturer, ps_stock |
group:system | database, ps_log, ps_config, ps_module, ps_employee, ps_report |
Approval and PHP files
Section titled “Approval and PHP files”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.
# one-shot sendphp 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-4ophp modules/phpclaw/cli/phpclaw.php send "and which of them are out of stock?" --continue --tracephp modules/phpclaw/cli/phpclaw.php send "and the rest?" --conv-id=<id>
# interactive chatphp modules/phpclaw/cli/phpclaw.php chatphp modules/phpclaw/cli/phpclaw.php chat --continuephp modules/phpclaw/cli/phpclaw.php chat --conv-id=<id>
php modules/phpclaw/cli/phpclaw.php mcp-serversend 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.
One-shot options and the chat session
Section titled “One-shot options and the chat session”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:
| Command | What it does |
|---|---|
/help | List these commands |
/tools | List the active tools |
/model <name> | Switch the model for this session only |
/provider <slug> | Switch the provider for this session only |
/new | Start a new conversation |
/conv | Print the conversation id |
/quiet | Turn the tool trace off or on |
/clear | Clear the screen |
/exit | Leave; 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”.
REST endpoint
Section titled “REST endpoint”One front controller, with the action in the query string:
| Action | URL | Returns |
|---|---|---|
send | {shop}/index.php?fc=module&module=phpclaw&controller=api&action=send | the reply as JSON |
chat/stream | {shop}/index.php?fc=module&module=phpclaw&controller=api&action=chat/stream | Server-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.
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?"}'Authentication
Section titled “Authentication”- 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
viewon the Chat tab. Only theAuthorizationheader 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
viewon the Chat tab, from a same-origin request.
Responses
Section titled “Responses”| Status | Code | When |
|---|---|---|
| 400 | phpclaw_empty_message, phpclaw_long_message | the message is missing or too long |
| 403 | phpclaw_forbidden | not authenticated, no Chat grant, or another employee’s conversation |
| 404 | phpclaw_not_found | unknown action |
| 405 | phpclaw_forbidden | not a POST |
| 422 | phpclaw_guard | a guard blocked the message |
| 422 | phpclaw_budget_exceeded | the token budget was reached: “Token budget reached for this run.” |
| 429 | phpclaw_rate_limited | more 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.”) |
| 500 | phpclaw_error | anything else failed |
| 503 | phpclaw_not_configured | no 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.
Admin pages
Section titled “Admin pages”| Page | Tab permission | Shows |
|---|---|---|
| Settings | Settings | the settings, Test Connection, and API tokens for SuperAdmins |
| Chat | Chat | the chat interface with the employee’s conversations |
| Analytics | Analytics | conversation and message counts; store-wide for SuperAdmins, otherwise the employee’s own |
| Guide | Guide | the registered tools |
| About | About | module information |
Conversations and ownership
Section titled “Conversations and ownership”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).
Extending
Section titled “Extending”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:
| Hook | Adds |
|---|---|
actionPhpclawExtraTools | tools |
actionPhpclawExtraGuards | guards |
actionPhpclawExtraHooks | lifecycle listeners |
actionPhpclawExtraSkills | skills |
actionPhpclawExtraMemory | memory drivers |
actionPhpclawExtraProviders | providers |
Lifecycle events
Section titled “Lifecycle events”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.