@xmarts/genius-setup 1.10.0 → 1.11.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/genius-setup.js +27 -0
- package/package.json +3 -2
- package/plugin/skills/genius-operator/SKILL.md +178 -0
- package/plugin/skills/genius-operator/references/deploy-webapp-to-client.md +183 -0
- package/plugin/skills/genius-operator/references/manage-client-modules.md +106 -0
- package/plugin/skills/genius-operator/references/tool-catalog.md +129 -0
package/bin/genius-setup.js
CHANGED
|
@@ -225,6 +225,32 @@ function runSetup(token) {
|
|
|
225
225
|
log('WARN: could not write CLAUDE.md protocol (' + e.message + ')');
|
|
226
226
|
}
|
|
227
227
|
|
|
228
|
+
// 4b) ~/.claude/skills — install the bundled Genius skills so `token+npm` REALLY
|
|
229
|
+
// delivers skills too (previously only hooks+MCP shipped, though the footer
|
|
230
|
+
// already claimed skills arrived — this closes that gap). plugin/skills is the
|
|
231
|
+
// git source-of-truth mirror; copy each skill dir into ~/.claude/skills/<name>/,
|
|
232
|
+
// refreshing ours without clobbering the consultant's own skills. Fails open.
|
|
233
|
+
let skillsInstalled = [];
|
|
234
|
+
try {
|
|
235
|
+
const SKILLS_SRC = path.join(__dirname, '..', 'plugin', 'skills');
|
|
236
|
+
const SKILLS_DST = path.join(CLAUDE_DIR, 'skills');
|
|
237
|
+
if (fs.existsSync(SKILLS_SRC)) {
|
|
238
|
+
ensureDir(SKILLS_DST);
|
|
239
|
+
for (const name of fs.readdirSync(SKILLS_SRC)) {
|
|
240
|
+
const src = path.join(SKILLS_SRC, name);
|
|
241
|
+
try {
|
|
242
|
+
if (!fs.statSync(src).isDirectory()) continue;
|
|
243
|
+
fs.cpSync(src, path.join(SKILLS_DST, name), { recursive: true, force: true });
|
|
244
|
+
skillsInstalled.push(name);
|
|
245
|
+
} catch (e) {
|
|
246
|
+
log('WARN: could not install skill ' + name + ' (' + e.message + ')');
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
} catch (e) {
|
|
251
|
+
log('WARN: could not install skills (' + e.message + ')');
|
|
252
|
+
}
|
|
253
|
+
|
|
228
254
|
// 5) Fan out the consultant's OTHER MCP servers (asana, clickup, google, ...).
|
|
229
255
|
// Their non-secret shape (manifest) + per-device secret VALUES come from the
|
|
230
256
|
// Bearer-authed /xma/genius/v1/mcp/secrets endpoint. We write Claude Code
|
|
@@ -325,6 +351,7 @@ function runSetup(token) {
|
|
|
325
351
|
log(' - Presence : ' + presenceDst + ' (SessionStart, detached — honest time-tracking amarre)');
|
|
326
352
|
log(' - Config : ' + path.join(GENIUS_DIR, 'config.json'));
|
|
327
353
|
log(' - Protocol : ' + path.join(CLAUDE_DIR, 'CLAUDE.md') + ' (auto-managed)');
|
|
354
|
+
if (skillsInstalled.length) log(' - Skills : ' + path.join(CLAUDE_DIR, 'skills') + ' (' + skillsInstalled.join(', ') + ')');
|
|
328
355
|
if (CLIENT) log(' - Default client : ' + CLIENT);
|
|
329
356
|
log('');
|
|
330
357
|
log(' Restart Claude Code. Per-turn Brain injection + automatic capture + the Genius');
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@xmarts/genius-setup",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.11.0",
|
|
4
4
|
"description": "One-command, self-updating onboarding for Xmarts Genius (Brain MCP + per-turn injection + automatic session/time capture + presence heartbeat for honest time-tracking 'amarre' + plan/committee→Brain enforcement + CLAUDE.md protocol + MCP fan-out: provisions the consultant's granted MCP servers into Claude Code & Claude Desktop). Secret-free onboarding via single-use setup-token exchange. Installs once; self-updates daily so new tools/skills/features arrive with zero action.",
|
|
5
5
|
"bin": {
|
|
6
6
|
"genius-setup": "bin/genius-setup.js"
|
|
@@ -12,7 +12,8 @@
|
|
|
12
12
|
"hooks/plan_committee_guard.py",
|
|
13
13
|
"hooks/genius_presence.py",
|
|
14
14
|
"CLAUDE_PROTOCOL.md",
|
|
15
|
-
"README.md"
|
|
15
|
+
"README.md",
|
|
16
|
+
"plugin/skills"
|
|
16
17
|
],
|
|
17
18
|
"engines": {
|
|
18
19
|
"node": ">=16"
|
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: genius-operator
|
|
3
|
+
description: >
|
|
4
|
+
Operate the Xmarts Genius platform from any session: read, write, deploy webapps,
|
|
5
|
+
deploy/manage modules, snapshot, restore and restart Odoo — on the BeeSmart central
|
|
6
|
+
OR on ANY registered client Odoo (GEA, Elevatrix, Deploy-O, etc.) through the
|
|
7
|
+
`beesmart_genius` MCP. The key unlock most sessions miss: every Genius tool accepts a
|
|
8
|
+
`target_client` parameter that routes the SAME call to a client's Odoo over the secure
|
|
9
|
+
HMAC gateway. Use this skill whenever a session says it "can't" reach a client, can't
|
|
10
|
+
deploy a webapp to a client, can't see/manage a client's modules, or whenever the work
|
|
11
|
+
touches xma_genius, xma_connect, beesmart_genius, the Genius Brain, GEA Ecuador, or
|
|
12
|
+
deploying/controlling anything on a client instance from the central — even if the user
|
|
13
|
+
doesn't name the tool. If you ever think "I don't have access to that client", read this
|
|
14
|
+
skill first: you almost certainly do.
|
|
15
|
+
---
|
|
16
|
+
|
|
17
|
+
# Genius Operator
|
|
18
|
+
|
|
19
|
+
You are operating the **Xmarts Genius** platform. Genius is a central command server
|
|
20
|
+
(module `xma_genius`, living on `beesmart.digital`) that controls a fleet of client Odoo
|
|
21
|
+
instances. Each client runs a thin agent (`xma_connect`) that exposes a signed HMAC gateway.
|
|
22
|
+
You reach all of it through one MCP server: **`beesmart_genius`**.
|
|
23
|
+
|
|
24
|
+
This skill exists to kill one specific failure: sessions saying *"no puedo hacer eso / I
|
|
25
|
+
don't have access to that client"* when they actually can. They can. They just didn't set
|
|
26
|
+
one parameter.
|
|
27
|
+
|
|
28
|
+
## The one thing to internalize: `target_client`
|
|
29
|
+
|
|
30
|
+
Almost every `mcp__beesmart_genius__*` tool takes an optional **`target_client`** argument.
|
|
31
|
+
|
|
32
|
+
- **Omit it** → the call runs on the BeeSmart central (`odoo_clean` DB).
|
|
33
|
+
- **Set it** to a client's name or UUID → the EXACT same call is signed (HMAC-SHA256) and
|
|
34
|
+
routed through that client's `xma_connect` gateway, executing on *their* Odoo and returning
|
|
35
|
+
the result to you.
|
|
36
|
+
|
|
37
|
+
```
|
|
38
|
+
# Reads the central Brain on beesmart:
|
|
39
|
+
execute_orm(code="result = env['xma.learning'].search_count([])")
|
|
40
|
+
|
|
41
|
+
# Reads GEA Ecuador's live Odoo — same tool, one extra arg:
|
|
42
|
+
execute_orm(code="result = env['sale.order'].search_count([])", target_client="GEA Ecuador")
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
That is the whole trick. A session is **not** sandboxed to beesmart. With `target_client`
|
|
46
|
+
it can read data, write records, deploy webapps, install/upgrade modules, snapshot, restore,
|
|
47
|
+
and restart Odoo on any *registered, connected* client. When you catch yourself about to say
|
|
48
|
+
"I can't do that on the client," stop and set `target_client` instead.
|
|
49
|
+
|
|
50
|
+
`target_client` accepts either the human name (`"GEA Ecuador"`) or the UUID
|
|
51
|
+
(`"74292458-44e8-406c-a476-4e89f86920c8"`). The name is matched on the central's `xma.client`
|
|
52
|
+
registry, so it must match an existing record.
|
|
53
|
+
|
|
54
|
+
## "Can I actually do X?" — yes, here's the map
|
|
55
|
+
|
|
56
|
+
When in doubt, this table answers it. The full per-tool reference with quirks is in
|
|
57
|
+
[references/tool-catalog.md](references/tool-catalog.md) — read it when you need the exact
|
|
58
|
+
argument shape or hit an edge case.
|
|
59
|
+
|
|
60
|
+
| You want to… | Tool | Routable to a client? |
|
|
61
|
+
|---|---|---|
|
|
62
|
+
| Run arbitrary ORM/Python (read or write) | `execute_orm` | ✅ `target_client` |
|
|
63
|
+
| Search / read records | `search_read`, `read_record`, `read_group` | ✅ |
|
|
64
|
+
| Create / update / delete a record | `create_record`, `update_record`, `delete_record` | ✅ |
|
|
65
|
+
| Call a model method | `execute_method` | ✅ |
|
|
66
|
+
| Deploy / edit a **webapp** | `manage_webapp` | ✅ **only if the client has the webapp infra installed — probe first** (see below + [deploy-webapp-to-client.md](references/deploy-webapp-to-client.md)) |
|
|
67
|
+
| Deploy / install / upgrade a **module** | `manage_module`, `deploy_module` | ✅ — see [manage-client-modules.md](references/manage-client-modules.md) |
|
|
68
|
+
| Inspect a model's schema | `get_model_schema`, `list_models` | ✅ |
|
|
69
|
+
| Read / search a client's source code | `code_read`, `code_search`, `search_webapp_code` | ✅ |
|
|
70
|
+
| Snapshot / restore / export the DB | `create_snapshot`, `restore_snapshot`, `export_database` | ✅ |
|
|
71
|
+
| Restart Odoo | `trigger_restart` | ✅ |
|
|
72
|
+
| Build a chart/dashboard | `create_echart` | ✅ *(same infra caveat as webapps)* |
|
|
73
|
+
| Query the Genius **Brain** | `query_knowledge` | ❌ central only (the Brain lives on beesmart) |
|
|
74
|
+
| Capture a learning to the Brain | `capture_learning` | ❌ central only |
|
|
75
|
+
| Read your own consultant profile | `get_my_profile` | ❌ central only |
|
|
76
|
+
|
|
77
|
+
33 tools are routable to clients in total. If a tool you need isn't listed, check
|
|
78
|
+
[references/tool-catalog.md](references/tool-catalog.md) before concluding it's impossible.
|
|
79
|
+
|
|
80
|
+
## Always orient before you act
|
|
81
|
+
|
|
82
|
+
The Brain (`query_knowledge`) is the server-side source of truth and it remembers things this
|
|
83
|
+
session doesn't. It has saved you from real footguns (downgrade bricking, version desync,
|
|
84
|
+
auth gotchas). So:
|
|
85
|
+
|
|
86
|
+
1. **`query_knowledge(<your task topic>)` before building or debugging.** Two minutes here
|
|
87
|
+
beats an hour of rediscovering a known trap.
|
|
88
|
+
2. Check the client is actually reachable before routing to it. A quick
|
|
89
|
+
`execute_orm(code="result = True", target_client="<name>")` round-trips the gateway. If it
|
|
90
|
+
errors with `auth_invalid` / `Not configured`, the client has a master↔client api_key
|
|
91
|
+
desync — that's a known issue, query the Brain for "Not configured gateway api_key desync"
|
|
92
|
+
rather than guessing.
|
|
93
|
+
3. After a notable build or fix, **`capture_learning(...)`** so the next session inherits it.
|
|
94
|
+
Required shape: `name` + `category` (one of `breaking_change | pattern | antipattern |
|
|
95
|
+
workaround | best_practice`) + `resolution`; `tags` is a comma-separated **string**.
|
|
96
|
+
|
|
97
|
+
## Hard rules (these are non-negotiable and protect production)
|
|
98
|
+
|
|
99
|
+
These come straight from the Xmarts operating doctrine — follow them even when not asked:
|
|
100
|
+
|
|
101
|
+
- **Snapshot before any write to a client's production data.** Use `create_snapshot`
|
|
102
|
+
(`target_client=...`) first. The orchestrated `deploy_module` auto-snapshots; manual
|
|
103
|
+
`update_record`/`execute_orm` writes do not — you take the snapshot. No snapshot → don't run
|
|
104
|
+
the change.
|
|
105
|
+
- **Never destroy productive data.** Archive with `active=False`, never `unlink()`/delete.
|
|
106
|
+
It's reversible and keeps the audit trail.
|
|
107
|
+
- **Everything is Odoo 19.** Generate only v19-compatible code (e.g. `<list>` not `<tree>`,
|
|
108
|
+
`models.Constraint` not `_sql_constraints`, `group_ids` not `groups_id`). When unsure,
|
|
109
|
+
`code_search` the client's own source to confirm the API before you write it.
|
|
110
|
+
- **Webapps are mobile-first and theme-driven.** No hardcoded hex colors — colors flow from
|
|
111
|
+
the theme. Don't hand-roll a webapp from scratch here; use the dedicated skills (below) to
|
|
112
|
+
build it well, then this skill to *deploy* it to the right place.
|
|
113
|
+
- **Credentials never inline.** No api_keys/passwords in tool arguments or committed code.
|
|
114
|
+
|
|
115
|
+
## Webapps: build with the specialists, deploy with this skill
|
|
116
|
+
|
|
117
|
+
This skill's job for webapps is the **routing and deployment** layer — getting the right app
|
|
118
|
+
onto the right Odoo (central vs a specific client) and verifying it serves. For the actual
|
|
119
|
+
*construction* quality (design, theming, mobile-first, audit), hand off to the specialists:
|
|
120
|
+
|
|
121
|
+
- `webapp-forge` — prompt → mockup → theme → React → deploy pipeline
|
|
122
|
+
- `webapp-theming-system` — OKLCH themes, dark mode, WCAG contrast
|
|
123
|
+
- `webapp-refine` — iterate on an existing webapp
|
|
124
|
+
- `webapp-audit` — 6-point quality gate before you call it done
|
|
125
|
+
- `xmarts-kanban-standard` — the mandatory kanban card look
|
|
126
|
+
|
|
127
|
+
**Prerequisite — probe the client's capability first, do NOT trust the version number.**
|
|
128
|
+
Webapp deploy to a client only works if that client's `xma_connect` actually ships *and loads*
|
|
129
|
+
the webapp infra (the `mcp.webapp*` models + the `/mcp/webapp` controller + the `manage_webapp`
|
|
130
|
+
gateway handler). The reported `xma_connect_version` is **not** a reliable gate — a stale-
|
|
131
|
+
constant bug and divergent deployed bundles mean a client labelled "5.0.0" may lack the infra
|
|
132
|
+
even though git added it at 4.0.0. So before deploying, route this probe:
|
|
133
|
+
|
|
134
|
+
```
|
|
135
|
+
execute_orm(code="result = bool(env['ir.model'].search([('model','=','mcp.webapp')], limit=1))",
|
|
136
|
+
target_client="<client>")
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
`false` → the client can't host a webapp yet; it needs an `xma_connect` upgrade that ships and
|
|
140
|
+
loads the webapp infra first (and on some clients that upgrade is itself gated). Probe every
|
|
141
|
+
time, because **state changes**: GEA Ecuador returned `false` at `xma_connect` 5.0.0, then was
|
|
142
|
+
upgraded to 8.0.0 (Deploy-O parity) and now returns `true`. Never hard-code "client X can/can't"
|
|
143
|
+
from memory — the version field lies and clients get upgraded; the live probe is the truth.
|
|
144
|
+
|
|
145
|
+
The deploy mechanics, the data-flow gotcha that bites everyone (page `data_code` vs webapp
|
|
146
|
+
`data_code`), the slug/URL model, and the client-vs-central decision are all in
|
|
147
|
+
[references/deploy-webapp-to-client.md](references/deploy-webapp-to-client.md). Read it before
|
|
148
|
+
your first deploy to a client.
|
|
149
|
+
|
|
150
|
+
## Modules: controlling what Xmarts builds for a client (the GEA case)
|
|
151
|
+
|
|
152
|
+
When a client like GEA accumulates many Xmarts-built modules, this is how you keep control of
|
|
153
|
+
them from the central — list installed modules, read their source, deploy new ones, upgrade,
|
|
154
|
+
snapshot before each change, and roll back if needed. The full workflow, including the
|
|
155
|
+
orchestrated `deploy_module` (pre-checks + auto-snapshot + post-checks) and when a
|
|
156
|
+
Python-bearing module needs the SSH path instead of `manage_module`, is in
|
|
157
|
+
[references/manage-client-modules.md](references/manage-client-modules.md).
|
|
158
|
+
|
|
159
|
+
The short version: `module_list_installed` / `manage_module` (info) to see what's there,
|
|
160
|
+
`code_read` + `code_search` to inspect it, `deploy_module` to ship changes safely. Always
|
|
161
|
+
validate a non-trivial module on a clean Odoo 19 env first — green install ≠ correct.
|
|
162
|
+
|
|
163
|
+
## When a session is stuck saying "I can't"
|
|
164
|
+
|
|
165
|
+
Diagnose in this order — it's almost always #1 or #2:
|
|
166
|
+
|
|
167
|
+
1. **Did it set `target_client`?** Most "I can't reach the client" cases are just a missing
|
|
168
|
+
parameter. Add it.
|
|
169
|
+
2. **Is the MCP authenticated?** The `beesmart_genius` tools must be loaded. If they aren't
|
|
170
|
+
visible, the session needs the MCP connected (and OAuth doesn't always persist between
|
|
171
|
+
sessions). Reconnect, don't give up.
|
|
172
|
+
3. **Is the client connected?** Round-trip a trivial `execute_orm` to it. If `Not configured`,
|
|
173
|
+
it's the known api_key desync — query the Brain, don't reinvent.
|
|
174
|
+
4. **Is the tool genuinely central-only?** Only Brain tools (`query_knowledge`,
|
|
175
|
+
`capture_learning`, `get_my_profile`) are. Everything operational is routable.
|
|
176
|
+
|
|
177
|
+
Only after all four genuinely fail is "I can't" the honest answer — and then say *why*,
|
|
178
|
+
specifically, not just "no puedo".
|
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
# Deploying a webapp to a client (or central) via Genius
|
|
2
|
+
|
|
3
|
+
This is the routing/deployment layer. Build the webapp's quality (design, theme, mobile-first,
|
|
4
|
+
audit) with the specialist skills — `webapp-forge`, `webapp-theming-system`, `webapp-refine`,
|
|
5
|
+
`webapp-audit`, `xmarts-kanban-standard`. This file is about getting the right app onto the
|
|
6
|
+
right Odoo and confirming it serves.
|
|
7
|
+
|
|
8
|
+
## Table of contents
|
|
9
|
+
- [Prerequisite: the client must HAVE the webapp infra (probe it)](#prerequisite-probe-the-client)
|
|
10
|
+
- [Central vs client: decide first](#central-vs-client-decide-first)
|
|
11
|
+
- [The data model](#the-data-model)
|
|
12
|
+
- [The gotcha that bites everyone: data_code lives on the PAGE](#the-gotcha-data_code-lives-on-the-page)
|
|
13
|
+
- [Deploy recipe](#deploy-recipe)
|
|
14
|
+
- [Verify it serves](#verify-it-serves)
|
|
15
|
+
- [Editing an existing webapp](#editing-an-existing-webapp)
|
|
16
|
+
- [Quality gates before you call it done](#quality-gates)
|
|
17
|
+
|
|
18
|
+
## Prerequisite: probe the client
|
|
19
|
+
|
|
20
|
+
A client can only host a webapp if its `xma_connect` actually ships **and loads** the webapp
|
|
21
|
+
infra: the models `mcp.webapp` / `mcp.webapp.page` / `mcp.webapp.page.file` /
|
|
22
|
+
`mcp.webapp.endpoint` / `mcp.webapp.theme`, the `/mcp/webapp/...` controller, and the
|
|
23
|
+
`manage_webapp` gateway handler. The webapp infra was added to `xma_connect` at v19.0.4.0.0,
|
|
24
|
+
but **do not gate on the version number** — it lies. A stale-constant version bug plus divergent
|
|
25
|
+
deployed bundles (an older "5.0.0" served as newest) mean a client can report a version that
|
|
26
|
+
*should* have the infra and still not have it. Probe the ground truth instead:
|
|
27
|
+
|
|
28
|
+
```
|
|
29
|
+
execute_orm(code="result = bool(env['ir.model'].search([('model','=','mcp.webapp')], limit=1))",
|
|
30
|
+
target_client="<client>")
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
- `true` → infra present, proceed.
|
|
34
|
+
- `false` → the client cannot host a webapp yet. It needs an `xma_connect` upgrade that ships
|
|
35
|
+
and loads the webapp models first. Don't attempt `manage_webapp` against it — it will fail
|
|
36
|
+
on a missing model. Say so explicitly and, if asked, scope the upgrade (which on some clients
|
|
37
|
+
is itself a gated rollout).
|
|
38
|
+
|
|
39
|
+
**Why this is probe-not-version:** GEA Ecuador once returned `false` at `xma_connect` 5.0.0
|
|
40
|
+
(webapp models absent), and was later upgraded to 8.0.0 — it now returns `true` (full infra,
|
|
41
|
+
Deploy-O parity). The version field is unreliable AND clients get upgraded out from under you,
|
|
42
|
+
so the only safe gate is the live probe. If a client's probe is `false`, it needs an
|
|
43
|
+
`xma_connect` upgrade that ships + loads the webapp infra (on big/gated clients that upgrade
|
|
44
|
+
has its own rollout window); until then a "client webapp" can only live on the central reading
|
|
45
|
+
the client's data over the gateway (slower, fragile).
|
|
46
|
+
|
|
47
|
+
## Central vs client: decide first
|
|
48
|
+
|
|
49
|
+
`manage_webapp` writes `mcp.webapp` records wherever the call lands:
|
|
50
|
+
|
|
51
|
+
- **No `target_client`** → webapp lives on BeeSmart central, served at
|
|
52
|
+
`https://beesmart.digital/mcp/webapp/<slug>`. Use for Genius's own admin/consultant tools.
|
|
53
|
+
- **`target_client="<client>"`** (one whose probe returned `true`) → webapp lives on that
|
|
54
|
+
client's Odoo, served at `https://<client-domain>/mcp/webapp/<slug>`. Use for anything the
|
|
55
|
+
client's own users see, or any app that needs the client's live data.
|
|
56
|
+
|
|
57
|
+
Rule of thumb: if the app reads/writes the client's business data (their sales, their
|
|
58
|
+
inventory), deploy it ON the client with `target_client`. Routing a central webapp to read
|
|
59
|
+
client data over the gateway per request is slower and fragile — put the app where the data is.
|
|
60
|
+
|
|
61
|
+
The client must have `xma_connect` installed and connected **with the webapp infra present**
|
|
62
|
+
for client deploys (see the prerequisite probe above). Don't assume a given client's state from
|
|
63
|
+
memory — it changes (GEA went from no-infra to full infra after an upgrade). Probe, then decide.
|
|
64
|
+
|
|
65
|
+
## Visibility & RBAC (xma_connect ≥ 19.0.9.0.0) — PROBE → CHOOSE → DEPLOY → VERIFY
|
|
66
|
+
|
|
67
|
+
Newer `xma_connect` gates every webapp natively by a `visibility` field
|
|
68
|
+
(`public` / `internal` / `groups` / `users`, default **internal**), enforced by `ir.rule` +
|
|
69
|
+
route auth — no self-gating inside `data_code`. The contract for every deploy:
|
|
70
|
+
|
|
71
|
+
1. **PROBE** the client supports it: `search_read(model="ir.model", domain=[["model","=","mcp.webapp"]], ...)` exists, and check `mcp.webapp._fields` has `visibility` (xma_connect ≥ 9.0.0). Older clients have no visibility model → upgrade first.
|
|
72
|
+
2. **CHOOSE** visibility explicitly on EVERY `manage_webapp` create — never omit (omitting defaults to `internal`, which is safe but be deliberate):
|
|
73
|
+
- `internal` (default): any logged-in internal user.
|
|
74
|
+
- `groups`: pass `shared_group_ids` (native `res.groups`); add `base.group_portal` for portal users.
|
|
75
|
+
- `users`: pass `shared_user_ids`.
|
|
76
|
+
- `public`: anyone, no login — requires BOTH `visibility:"public"` **and** `public_confirm:true` in the SAME call, plus `public_model_allowlist` for any model the data reads. The tool rejects public without confirm.
|
|
77
|
+
- **Do NOT** write `env.user.has_group(...)`/`res.users` self-gates in `data_code` — the native rule gates; a self-gate just double-gates and 403s anonymous.
|
|
78
|
+
3. **DEPLOY** with the explicit visibility; the tool result echoes `visibility` + `access_summary` ("who can see this") — read it back.
|
|
79
|
+
4. **VERIFY** by fetching `/mcp/webapp/<slug>/page/<id>/data` (or the app URL) **as anonymous AND as an internal user**: an `internal` app must 401/redirect anonymous (no traceback); a `public` app must render for anonymous with its blast radius == the allowlist.
|
|
80
|
+
|
|
81
|
+
**Public forms / notice boards:** public `data_code` runs in a locked sandbox (no `.sudo()`, only allowlisted models). To accept submissions, set the endpoint `allow_public:true` + `submit_fields` and call `submit({...})` in `handler_code` — it writes one `mcp.webapp.submission` (staff-only) and returns an opaque ref. Anonymous calls are rate-limited per IP/min.
|
|
82
|
+
|
|
83
|
+
## The data model
|
|
84
|
+
|
|
85
|
+
```
|
|
86
|
+
mcp.webapp # the app: name, slug, router_mode, theme, PWA, shared styles/components
|
|
87
|
+
└── mcp.webapp.page # a route: route_path, component_code (React), data_code (Python)
|
|
88
|
+
└── mcp.webapp.page.file # extra JS/JSX files injected before the page component
|
|
89
|
+
mcp.webapp.endpoint # api.get/post/... handlers (handler_code, safe_eval Python)
|
|
90
|
+
mcp.webapp.theme # theme tokens (OKLCH); colors flow from here — never hardcode hex
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
`component_code` is React (props: `{data, routeParams, globalState, setGlobalState,
|
|
94
|
+
initialData, api, storage}`). `data_code` / `handler_code` are safe_eval Python with the SAME
|
|
95
|
+
rules and pre-imports as `execute_orm` — assign to `result`, no `import`, use
|
|
96
|
+
`env['mcp.webapp'].browse(mcp_webapp_id)`, never hardcode IDs or slugs.
|
|
97
|
+
|
|
98
|
+
## The gotcha: `data_code` lives on the PAGE
|
|
99
|
+
|
|
100
|
+
The single most common reason a deployed page shows no data: the component reads its data from
|
|
101
|
+
the **page's** `data_code`, not the webapp's. The webapp-level `data_code` only feeds
|
|
102
|
+
`initialData` on app load. If your page needs records, put the query in that **page's**
|
|
103
|
+
`data_code` and read it from the `data` prop.
|
|
104
|
+
|
|
105
|
+
When you edit data logic, update the PAGE's `data_code` (and if you also keep a copy at webapp
|
|
106
|
+
level, update both — they drift otherwise). This has burned multiple sessions.
|
|
107
|
+
|
|
108
|
+
## Deploy recipe
|
|
109
|
+
|
|
110
|
+
1. **Pick the target.** Central or `target_client`? (see above)
|
|
111
|
+
2. **If targeting a client, run the capability probe** (`mcp.webapp` exists?). `false` → stop,
|
|
112
|
+
the client needs an agent upgrade first.
|
|
113
|
+
4. **`query_knowledge("webapp deploy <client> <topic>")`** — pick up known gotchas first.
|
|
114
|
+
5. **Snapshot if it's a client with anything to lose.** `create_snapshot(target_client=...)`.
|
|
115
|
+
Creating a brand-new webapp is additive and low-risk; still cheap insurance on production.
|
|
116
|
+
6. **Create the webapp shell**, then pages/endpoints. You can do it in one `manage_webapp`
|
|
117
|
+
call combining `create_webapp` + `create_pages` + `create_endpoints`:
|
|
118
|
+
|
|
119
|
+
```
|
|
120
|
+
manage_webapp(
|
|
121
|
+
target_client="<client-with-webapp-infra>",
|
|
122
|
+
create_webapp={
|
|
123
|
+
"name": "GEA Ops Dashboard",
|
|
124
|
+
"slug": "gea-ops",
|
|
125
|
+
"router_mode": "hash", # hash works everywhere; "browser" needs a slug + clean URLs
|
|
126
|
+
"pwa_enabled": True, # mobile-first PWA is the Xmarts standard
|
|
127
|
+
"tailwind_enabled": True
|
|
128
|
+
},
|
|
129
|
+
create_pages=[{
|
|
130
|
+
"name": "Home",
|
|
131
|
+
"route_path": "/",
|
|
132
|
+
"component_code": "function Home({data}){ return <div className='p-4'>...</div> }",
|
|
133
|
+
"data_code": "result = {'orders': env['sale.order'].search_count([])}" # PAGE data_code!
|
|
134
|
+
}]
|
|
135
|
+
)
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
7. **Theme it** — don't hardcode colors. Hand off to `webapp-theming-system` or set the
|
|
139
|
+
`mcp.webapp.theme`. Colors must flow from theme tokens so dark/light both work.
|
|
140
|
+
8. **Verify** (next section).
|
|
141
|
+
9. **`capture_learning(...)`** if you hit and solved anything non-obvious.
|
|
142
|
+
|
|
143
|
+
For multi-step builds, create the shell first, then add pages/files in follow-up
|
|
144
|
+
`manage_webapp` calls (each can derive the webapp from a page/file id, so you don't have to
|
|
145
|
+
repeat `update_webapp`).
|
|
146
|
+
|
|
147
|
+
## Verify it serves
|
|
148
|
+
|
|
149
|
+
Don't declare done from the tool's success message alone — confirm the route actually renders:
|
|
150
|
+
|
|
151
|
+
```
|
|
152
|
+
# Confirm the record exists on the right instance:
|
|
153
|
+
search_read(model="mcp.webapp", domain=[["slug","=","my-app"]],
|
|
154
|
+
fields=["id","name","slug"], target_client="<client>", limit=5)
|
|
155
|
+
```
|
|
156
|
+
Then load `https://<client-domain>/mcp/webapp/my-app` (or have the user open it). A 200
|
|
157
|
+
with the rendered page = deployed. If the page is blank, re-check the **page** `data_code` and
|
|
158
|
+
the browser console for a component error.
|
|
159
|
+
|
|
160
|
+
## Editing an existing webapp
|
|
161
|
+
|
|
162
|
+
Read before you write — use `search_read`/`read_record` (with `target_client`) to get current
|
|
163
|
+
code, then patch surgically:
|
|
164
|
+
|
|
165
|
+
```
|
|
166
|
+
# Discover pages:
|
|
167
|
+
search_read(model="mcp.webapp.page", domain=[["webapp_id","=",ID]],
|
|
168
|
+
fields=["id","name","route_path"], target_client="<client>", limit=50)
|
|
169
|
+
# Read full code:
|
|
170
|
+
read_record(model="mcp.webapp.page", id=PAGE_ID,
|
|
171
|
+
fields=["component_code","data_code"], target_client="<client>")
|
|
172
|
+
# Surgical edit (preferred over full rewrite):
|
|
173
|
+
manage_webapp(target_client="<client>",
|
|
174
|
+
update_pages=[{"page_id": PAGE_ID,
|
|
175
|
+
"component_code_patches": [{"find": "old snippet", "replace": "new snippet"}]}])
|
|
176
|
+
```
|
|
177
|
+
Use `search_webapp_code` to locate exact strings before patching.
|
|
178
|
+
|
|
179
|
+
## Quality gates
|
|
180
|
+
|
|
181
|
+
Before calling a webapp done, run the `webapp-audit` skill (PWA, WCAG contrast, no hardcoded
|
|
182
|
+
hex, CSS/JS budget, accessibility, dark mode). The Xmarts non-negotiables: mobile-first PWA,
|
|
183
|
+
44px touch targets, theme-driven colors, dark mode that actually flips, skeleton loading.
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
# Controlling a client's Xmarts-built modules (the GEA case)
|
|
2
|
+
|
|
3
|
+
GEA Ecuador will accumulate many modules built by Xmarts. This is how you keep central control
|
|
4
|
+
of them: see what's installed, read the source, ship changes safely, upgrade, and roll back —
|
|
5
|
+
all from the `beesmart_genius` MCP with `target_client="GEA Ecuador"`.
|
|
6
|
+
|
|
7
|
+
GEA facts to keep in mind: Odoo 19 Enterprise, ~474 modules installed, DB ≈ 14.8 GB (large —
|
|
8
|
+
exports/restores need a dedicated window), hosted on `geaecuador.xmarts.net`. Its `xma_connect`
|
|
9
|
+
was upgraded to 8.0.0 (Deploy-O parity) and now has the full webapp/dashboard infra — but
|
|
10
|
+
always probe `mcp.webapp` rather than trusting that statement, since state changes.
|
|
11
|
+
Files in `xma_connect`/custom addons on `xmarts.net` infra are often owned by root, so Odoo's
|
|
12
|
+
uid can't write — a true filesystem deploy may need an SSH `chown`. The gateway path below
|
|
13
|
+
avoids that for ZIP-importable modules.
|
|
14
|
+
|
|
15
|
+
## Table of contents
|
|
16
|
+
- [See what Xmarts has shipped](#1-see-whats-installed)
|
|
17
|
+
- [Inspect a module's source](#2-inspect-the-source)
|
|
18
|
+
- [Ship or upgrade a module](#3-ship-or-upgrade-a-module-safely)
|
|
19
|
+
- [manage_module vs deploy_module vs SSH](#which-path-data-vs-python)
|
|
20
|
+
- [Snapshot & rollback](#4-snapshot--rollback)
|
|
21
|
+
- [Restart when needed](#5-restart-when-the-registry-is-stale)
|
|
22
|
+
|
|
23
|
+
## 1. See what's installed
|
|
24
|
+
|
|
25
|
+
```
|
|
26
|
+
module_list_installed(target_client="GEA Ecuador")
|
|
27
|
+
```
|
|
28
|
+
Or filter to the Xmarts-built ones:
|
|
29
|
+
```
|
|
30
|
+
search_read(model="ir.module.module",
|
|
31
|
+
domain=[["state","=","installed"],["name","=like","xma%"]],
|
|
32
|
+
fields=["name","installed_version","summary","state"],
|
|
33
|
+
target_client="GEA Ecuador", order="name", limit=200)
|
|
34
|
+
```
|
|
35
|
+
This is your inventory of "what Xmarts built and shipped to GEA" and the live version of each.
|
|
36
|
+
(Remember the central's `xma.client.xma_connect_version` field is unreliable — read the real
|
|
37
|
+
versions from GEA like this instead.)
|
|
38
|
+
|
|
39
|
+
## 2. Inspect the source
|
|
40
|
+
|
|
41
|
+
```
|
|
42
|
+
# Find where something is defined across GEA's addons:
|
|
43
|
+
code_search(pattern="class .*Model|def action_", file_pattern="**/*.py",
|
|
44
|
+
output_mode="files_with_matches", limit=50, target_client="GEA Ecuador",
|
|
45
|
+
module="xma_<module>")
|
|
46
|
+
# Read a specific file (path from the addon root):
|
|
47
|
+
code_read(path="xma_<module>/models/<file>.py", target_client="GEA Ecuador")
|
|
48
|
+
```
|
|
49
|
+
For webapp/echart code shipped to GEA, use `search_webapp_code`.
|
|
50
|
+
|
|
51
|
+
## 3. Ship or upgrade a module safely
|
|
52
|
+
|
|
53
|
+
Prefer the orchestrated path — it snapshots automatically and runs pre/post checks:
|
|
54
|
+
|
|
55
|
+
```
|
|
56
|
+
deploy_module(target_client="GEA Ecuador", arguments={...module + options...})
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
`deploy_module` = pre-checks → auto-snapshot → install/upgrade → post-checks. This is the
|
|
60
|
+
right default for production because the snapshot and verification are built in.
|
|
61
|
+
|
|
62
|
+
For authoring/iterating a data/XML/CSV/webapp module, `manage_module` gives finer control:
|
|
63
|
+
- `create_module` + `create_files` (include `__manifest__.py` as a normal file).
|
|
64
|
+
- `skip_install=true` while adding files across several calls; `false` on the last call to
|
|
65
|
+
install.
|
|
66
|
+
- If an install fails, **files are saved but the install rolls back** — fix the broken file
|
|
67
|
+
with `update_files` and call again; you don't resubmit everything.
|
|
68
|
+
- `force=true` re-inits `noupdate=1` records. `uninstall_first=true` **drops all module data**
|
|
69
|
+
— destructive, ask the user before using it.
|
|
70
|
+
- Manifest is validated pre-install: every file in `data` must exist.
|
|
71
|
+
|
|
72
|
+
### Which path: data vs Python
|
|
73
|
+
|
|
74
|
+
| Module contents | Path | Why |
|
|
75
|
+
|---|---|---|
|
|
76
|
+
| XML / CSV / views / webapp / data only | `manage_module` or `deploy_module` (ZIP via `base_import_module`) | Installs cleanly over the gateway, no SSH. |
|
|
77
|
+
| Python that must execute at load (models, compute, controllers) | Validate on a **clean Odoo 19 EE env first**, then deploy. `base_import_module` does not reliably run arbitrary Python — a real filesystem deploy may be needed (SSH `chown` on `xmarts.net`). | Historically `manage_module` is data-only for code execution (Brain: "manage_module data-only confirmed"). Don't assume a Python module "installed" just because the call returned success — verify the model/fields actually exist. |
|
|
78
|
+
|
|
79
|
+
Always: a green install ≠ a correct module. After install, verify behavior — e.g.
|
|
80
|
+
`list_models` / `get_model_schema` for new models, or `execute_orm` exercising the new logic,
|
|
81
|
+
routed to GEA. For anything non-trivial, validate on the disposable clean env before GEA.
|
|
82
|
+
|
|
83
|
+
When generating module code, it's **Odoo 19** — `<list>` not `<tree>`, `models.Constraint` not
|
|
84
|
+
`_sql_constraints`, `group_ids` not `groups_id`, `hr.version` not `hr.contract`, fiscal tax
|
|
85
|
+
mappings on taxes not fiscal positions. `code_search` GEA's own source to confirm an API before
|
|
86
|
+
relying on it.
|
|
87
|
+
|
|
88
|
+
## 4. Snapshot & rollback
|
|
89
|
+
|
|
90
|
+
```
|
|
91
|
+
create_snapshot(target_client="GEA Ecuador") # before any change deploy_module didn't auto-snapshot
|
|
92
|
+
list_snapshots(target_client="GEA Ecuador") # confirm it exists
|
|
93
|
+
restore_snapshot(target_client="GEA Ecuador", ...) # the rollback — confirm with the user first
|
|
94
|
+
```
|
|
95
|
+
Register every snapshot per the snapshot protocol (name, UUID, type, size, trigger, storage).
|
|
96
|
+
On a 14.8 GB DB, snapshot/restore is heavy — plan the window, don't fire it mid-business-hours
|
|
97
|
+
without telling the user.
|
|
98
|
+
|
|
99
|
+
## 5. Restart when the registry is stale
|
|
100
|
+
|
|
101
|
+
Some upgrades change the in-memory registry; the running server keeps the old one until
|
|
102
|
+
restarted:
|
|
103
|
+
```
|
|
104
|
+
trigger_restart(target_client="GEA Ecuador")
|
|
105
|
+
```
|
|
106
|
+
Always restart after a `--stop-after-init` style upgrade so the new code is actually live.
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
# Genius Tool Catalog (`beesmart_genius` MCP)
|
|
2
|
+
|
|
3
|
+
The authoritative list of what you can do through Genius, what routes to a client, and the
|
|
4
|
+
quirks that trip people up. All tools are namespaced `mcp__beesmart_genius__<tool>`.
|
|
5
|
+
|
|
6
|
+
## Table of contents
|
|
7
|
+
- [Routing model](#routing-model)
|
|
8
|
+
- [Routable operational tools (run on central OR a client)](#routable-operational-tools)
|
|
9
|
+
- [Central-only tools (Brain & self)](#central-only-tools)
|
|
10
|
+
- [Cross-cutting quirks](#cross-cutting-quirks)
|
|
11
|
+
|
|
12
|
+
## Routing model
|
|
13
|
+
|
|
14
|
+
Every routable tool takes `target_client` (string: client name or UUID).
|
|
15
|
+
- Omitted → executes on BeeSmart central (`odoo_clean`).
|
|
16
|
+
- Set → signed HMAC-SHA256 request through the client's `xma_connect` gateway
|
|
17
|
+
(`/xma/gateway/v1`), executed under the client's non-admin **service user** (not superuser),
|
|
18
|
+
inside a savepoint that rolls back on error.
|
|
19
|
+
|
|
20
|
+
The client side dispatches through `ToolDispatcher` (33 registered handlers). If a tool isn't
|
|
21
|
+
in that set, it can't be routed — but every operational tool you'd want is.
|
|
22
|
+
|
|
23
|
+
Reachability self-test (cheap, safe, read-only):
|
|
24
|
+
```
|
|
25
|
+
execute_orm(code="result = {'ok': True, 'db': env.cr.dbname}", target_client="GEA Ecuador")
|
|
26
|
+
```
|
|
27
|
+
A clean `{success: true, ...}` means the gateway, HMAC auth and service user are all healthy.
|
|
28
|
+
`auth_invalid` / `Not configured` = master↔client api_key desync (known issue — query the
|
|
29
|
+
Brain: "Deploy-O gateway Not configured api_key desync", learning #1065).
|
|
30
|
+
|
|
31
|
+
## Routable operational tools
|
|
32
|
+
|
|
33
|
+
### Data read
|
|
34
|
+
| Tool | Use | Quirks |
|
|
35
|
+
|---|---|---|
|
|
36
|
+
| `search_read` | Search + read fields | Paginated — compare `count` vs `total`, use `offset`. Binary/image fields auto-base64'd as separate content. |
|
|
37
|
+
| `read_record` | One record by ID | Cheaper than `search_read` if you have the ID. |
|
|
38
|
+
| `read_group` | GROUP BY aggregation | v19: this is the supported aggregator (raw `read_group` ORM method is deprecated in favor of `_read_group`/`formatted_read_group`, but the MCP tool wraps it correctly). |
|
|
39
|
+
| `validate_domain` | Sanity-check a domain before a big query | Use on untrusted/long domains. |
|
|
40
|
+
|
|
41
|
+
### Data write
|
|
42
|
+
| Tool | Use | Quirks |
|
|
43
|
+
|---|---|---|
|
|
44
|
+
| `create_record` | Create one record | Simple creates only. |
|
|
45
|
+
| `update_record` | Write fields | **Snapshot first if production.** Archive via `active=False`, never delete. |
|
|
46
|
+
| `delete_record` | Delete | Avoid on productive data — prefer `active=False`. Ask the user before destructive deletes. |
|
|
47
|
+
| `execute_method` | Call any model method | For `action_confirm`, recompute, custom methods. Powerful — same write-safety rules apply. |
|
|
48
|
+
| `execute_orm` | Arbitrary safe_eval Python | The workhorse. NO `import`/`from` — utilities are pre-imported (`env`, `Command`, `datetime`, `requests`, `re`, `json`, `defaultdict`, `Counter`, etc.). Assign to `result`. Output cap ~100KB → paginate. `hasattr`/`getattr`/`__class__`/`dir` are blocked by safe_eval. |
|
|
49
|
+
| `bulk_execute` | Batch several operations | For multi-op efficiency. |
|
|
50
|
+
|
|
51
|
+
### Schema & code introspection
|
|
52
|
+
| Tool | Use |
|
|
53
|
+
|---|---|
|
|
54
|
+
| `get_model_schema` / `get_model_schema_progressive` | Field definitions. Filter by type / required to shrink output. |
|
|
55
|
+
| `list_models` | Enumerate models on the instance. |
|
|
56
|
+
| `code_read` | Read a source file by path (from addon root). |
|
|
57
|
+
| `code_search` | Regex search across addon source. `files_with_matches` to discover, then `code_read`. Paginate via `offset` (compare `returned` vs `total_*`). |
|
|
58
|
+
| `search_webapp_code` | Search inside `mcp.webapp` component/data code. |
|
|
59
|
+
| `get_system_info` | Odoo version, db, module counts, etc. |
|
|
60
|
+
|
|
61
|
+
### Webapps → see [deploy-webapp-to-client.md](deploy-webapp-to-client.md)
|
|
62
|
+
**Client-routed webapp/echart/design tools require the client's `xma_connect` to actually have
|
|
63
|
+
the `mcp.webapp*` / `mcp.echart` / `mcp.design.asset` infra installed.** This is NOT guaranteed
|
|
64
|
+
by the version number (see the version-truth quirk below) — probe first:
|
|
65
|
+
`execute_orm(code="result = bool(env['ir.model'].search([('model','=','mcp.webapp')], limit=1))", target_client="<client>")`.
|
|
66
|
+
A `false` means these three tools fail there until the agent is upgraded. State changes — GEA
|
|
67
|
+
returned `false` at 5.0.0 and `true` after its 8.0.0 upgrade — so probe each time, don't recall.
|
|
68
|
+
|
|
69
|
+
| Tool | Use |
|
|
70
|
+
|---|---|
|
|
71
|
+
| `manage_webapp` | Create/update webapps, pages, endpoints, page-files, assets. Surgical `*_patches` edits. Needs `mcp.webapp` infra on the client. |
|
|
72
|
+
| `create_echart` | Persistent ECharts 6.x dashboards. Needs `mcp.echart` on the client. |
|
|
73
|
+
| `manage_design_asset` | Manage `mcp.design.asset` (icons/SVGs). Needs `mcp.design.asset` on the client. |
|
|
74
|
+
|
|
75
|
+
### Modules → see [manage-client-modules.md](manage-client-modules.md)
|
|
76
|
+
| Tool | Use | Quirks |
|
|
77
|
+
|---|---|---|
|
|
78
|
+
| `module_list_installed` | List installed modules on the instance | Start here to see what Xmarts has shipped to a client. |
|
|
79
|
+
| `manage_module` | Create/install/upgrade/uninstall an importable module (ZIP via `base_import_module`) | Best for data/XML/CSV/webapp modules. `skip_install=true` for multi-step builds. `uninstall_first=true` is **destructive** — ask the user first. |
|
|
80
|
+
| `deploy_module` | Orchestrated deploy: pre-checks → **auto-snapshot** → install → post-checks | Preferred path for shipping a module to a client safely. |
|
|
81
|
+
| `module_manage_safe` | Guarded module ops | Safety wrapper. |
|
|
82
|
+
| `module_job_status` | Poll an async module job | For long installs. |
|
|
83
|
+
|
|
84
|
+
### DB lifecycle & ops
|
|
85
|
+
| Tool | Use | Quirks |
|
|
86
|
+
|---|---|---|
|
|
87
|
+
| `create_snapshot` | Snapshot the DB (and register it) | **Do this before any production write.** Register per the snapshot protocol (name, UUID, type, size, trigger). |
|
|
88
|
+
| `list_snapshots` | List snapshots | Verify a snapshot exists before a risky change. |
|
|
89
|
+
| `restore_snapshot` | Restore from a snapshot | The rollback. Confirm with the user. |
|
|
90
|
+
| `export_database` / `export_data` | Pull a full DB dump / dataset out | GEA is ~14.8GB — large-dump exports need a dedicated window. |
|
|
91
|
+
| `upload_attachment` | Push a binary into the instance | Base64 or URL. |
|
|
92
|
+
| `trigger_restart` / `trigger_restart` | Restart Odoo on the client | Needed after some module upgrades (registry lives in memory until restart). |
|
|
93
|
+
| `analyze_data` | Server-side analysis helper | — |
|
|
94
|
+
|
|
95
|
+
## Central-only tools
|
|
96
|
+
|
|
97
|
+
These have **no** `target_client` because they operate on Genius's own brain/registry:
|
|
98
|
+
|
|
99
|
+
| Tool | Use |
|
|
100
|
+
|---|---|
|
|
101
|
+
| `query_knowledge` | Vector search the Genius Brain (Gemini embeddings). Run BEFORE debugging/building. Filters: `category`, `odoo_version`. |
|
|
102
|
+
| `capture_learning` | Write a learning to the Brain. Required: `name` + `category` (`breaking_change\|pattern\|antipattern\|workaround\|best_practice`) + `resolution`. `tags` = comma-separated string. |
|
|
103
|
+
| `bulk_manage_learnings` / `update_learning` | Maintain learnings. |
|
|
104
|
+
| `get_my_profile` | Your consultant profile (specialty, leverage stats). Self-orient at session start. |
|
|
105
|
+
| `upload_code_graph` | Push a code-graph for a repo. |
|
|
106
|
+
|
|
107
|
+
Note: the central `xma.client` registry itself is just data on beesmart — read/manage it with a
|
|
108
|
+
plain (no-`target_client`) `execute_orm` / `search_read` on model `xma.client`.
|
|
109
|
+
|
|
110
|
+
## Cross-cutting quirks
|
|
111
|
+
|
|
112
|
+
- **Service user, not admin.** Client-routed calls run as the client's `service_user_id`
|
|
113
|
+
(a non-admin). Record rules apply. If a write is silently empty, it may be an ACL issue, not
|
|
114
|
+
a tool failure.
|
|
115
|
+
- **`SUPERUSER_ID` is rejected** for routed tool execution (security). Don't pass `user_id=1`.
|
|
116
|
+
- **Savepoint semantics.** A routed call that raises rolls back its savepoint — partial writes
|
|
117
|
+
won't persist, which is good, but means you must fix and re-run cleanly.
|
|
118
|
+
- **safe_eval limits** (in `execute_orm`, page `data_code`, endpoint `handler_code`): no
|
|
119
|
+
`import`, no `hasattr`/`getattr`/`__class__`/`dir`/`del`. Use the pre-imported names. Use
|
|
120
|
+
`datetime.datetime.now()` (datetime is the module). Test field presence with
|
|
121
|
+
`'field' in record._fields`, not `hasattr`.
|
|
122
|
+
- **Output ~100KB cap** on `execute_orm` — page large reads.
|
|
123
|
+
- **Version truth is unreliable on the central** for `xma_connect_version` (a known stale-
|
|
124
|
+
constant bug, plus divergent deployed bundles). To learn a client's REAL `xma_connect`
|
|
125
|
+
version, route an `execute_orm` reading
|
|
126
|
+
`env['ir.module.module'].search([('name','=','xma_connect')]).installed_version` to the
|
|
127
|
+
client — don't trust the central `xma.client.xma_connect_version` field. And because even the
|
|
128
|
+
real version can mislead (a "5.0.0" without the webapp infra that landed at 4.0.0), gate
|
|
129
|
+
feature availability on **probing the actual model/capability**, not on the version string.
|