@rubytech/create-siteoffice-code 0.1.263 → 0.1.265
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/package.json +1 -1
- package/payload/platform/plugins/admin/.claude-plugin/plugin.json +1 -1
- package/payload/platform/plugins/admin/PLUGIN.md +7 -2
- package/payload/platform/plugins/admin/mcp/dist/__tests__/skill-search.test.d.ts +2 -0
- package/payload/platform/plugins/admin/mcp/dist/__tests__/skill-search.test.d.ts.map +1 -0
- package/payload/platform/plugins/admin/mcp/dist/__tests__/skill-search.test.js +106 -0
- package/payload/platform/plugins/admin/mcp/dist/__tests__/skill-search.test.js.map +1 -0
- package/payload/platform/plugins/admin/mcp/dist/index.js +37 -2
- package/payload/platform/plugins/admin/mcp/dist/index.js.map +1 -1
- package/payload/platform/plugins/admin/mcp/dist/skill-resolution.d.ts +12 -0
- package/payload/platform/plugins/admin/mcp/dist/skill-resolution.d.ts.map +1 -1
- package/payload/platform/plugins/admin/mcp/dist/skill-resolution.js +175 -1
- package/payload/platform/plugins/admin/mcp/dist/skill-resolution.js.map +1 -1
- package/payload/platform/plugins/admin/skills/platform-architecture/SKILL.md +239 -239
- package/payload/platform/plugins/admin/skills/superpowers-sprint/SKILL.md +3 -3
- package/payload/platform/plugins/admin/skills/upgrade/SKILL.md +2 -2
- package/payload/platform/plugins/cloudflare/PLUGIN.md +1 -1
- package/payload/platform/plugins/cloudflare/references/manual-setup.md +10 -10
- package/payload/platform/plugins/cloudflare/references/reset-guide.md +1 -1
- package/payload/platform/plugins/docs/.claude-plugin/plugin.json +1 -1
- package/payload/platform/plugins/docs/PLUGIN.md +6 -6
- package/payload/platform/plugins/docs/references/admin-session.md +1 -1
- package/payload/platform/plugins/docs/references/admin-ui.md +2 -2
- package/payload/platform/plugins/docs/references/cloudflare.md +1 -1
- package/payload/platform/plugins/docs/references/deployment.md +7 -7
- package/payload/platform/plugins/docs/references/linkedin-extension.md +4 -4
- package/payload/platform/plugins/docs/references/memory-guide.md +2 -2
- package/payload/platform/plugins/docs/references/neo4j.md +1 -1
- package/payload/platform/plugins/docs/references/outlook-guide.md +1 -1
- package/payload/platform/plugins/docs/references/platform.md +2 -2
- package/payload/platform/plugins/docs/references/plugins-guide.md +6 -6
- package/payload/platform/plugins/docs/references/troubleshooting.md +1 -1
- package/payload/platform/plugins/linkedin-extension/.claude-plugin/plugin.json +1 -1
- package/payload/platform/plugins/linkedin-extension/PLUGIN.md +1 -1
- package/payload/platform/plugins/linkedin-extension/extension/README.md +4 -4
- package/payload/platform/plugins/linkedin-extension/extension/assets/pill.css +1 -1
- package/payload/platform/plugins/linkedin-extension/extension/content/profile.js +2 -2
- package/payload/platform/plugins/linkedin-extension/extension/content/thread.js +2 -2
- package/payload/platform/plugins/linkedin-extension/extension/manifest.json +3 -3
- package/payload/platform/plugins/linkedin-extension/extension/options/options.html +3 -3
- package/payload/platform/plugins/linkedin-import/.claude-plugin/plugin.json +1 -1
- package/payload/platform/plugins/linkedin-import/PLUGIN.md +2 -2
- package/payload/platform/plugins/memory/references/graph-primitives.md +1 -1
- package/payload/platform/plugins/memory/references/schema-base.md +1 -1
- package/payload/platform/plugins/memory/references/schema-construction.md +1 -1
- package/payload/platform/plugins/memory/skills/conversation-archive-mcp/SKILL.md +2 -2
- package/payload/platform/plugins/notion-import/.claude-plugin/plugin.json +1 -1
- package/payload/platform/plugins/notion-import/PLUGIN.md +2 -2
- package/payload/platform/plugins/obsidian-import/.claude-plugin/plugin.json +1 -1
- package/payload/platform/plugins/obsidian-import/PLUGIN.md +2 -2
- package/payload/platform/plugins/obsidian-import/skills/obsidian-import/SKILL.md +1 -1
- package/payload/platform/plugins/obsidian-import/skills/obsidian-import/references/attachments.md +1 -1
- package/payload/platform/plugins/obsidian-import/skills/obsidian-import/references/daily-notes.md +1 -1
- package/payload/platform/plugins/obsidian-import/skills/obsidian-import/references/vault-structure.md +1 -1
- package/payload/platform/plugins/obsidian-import/skills/obsidian-import/references/wikilinks.md +1 -1
- package/payload/platform/plugins/outlook/mcp/dist/index.js +1 -1
- package/payload/platform/plugins/outlook/references/auth.md +2 -2
- package/payload/platform/plugins/outlook/skills/outlook/SKILL.md +1 -1
- package/payload/platform/plugins/sales/.claude-plugin/plugin.json +1 -1
- package/payload/platform/plugins/sales/PLUGIN.md +8 -8
- package/payload/platform/plugins/sales/references/comparisons.md +18 -18
- package/payload/platform/plugins/sales/references/competitive-positioning.md +5 -5
- package/payload/platform/plugins/sales/references/faq.md +22 -22
- package/payload/platform/plugins/sales/references/objection-handling.md +3 -3
- package/payload/platform/plugins/sales/references/pricing.md +16 -16
- package/payload/platform/plugins/slides/PROVENANCE.md +1 -1
- package/payload/platform/plugins/substack-import/.claude-plugin/plugin.json +1 -1
- package/payload/platform/plugins/substack-import/PLUGIN.md +2 -2
- package/payload/platform/plugins/whatsapp/mcp/dist/__tests__/format-login-start.test.d.ts +2 -0
- package/payload/platform/plugins/whatsapp/mcp/dist/__tests__/format-login-start.test.d.ts.map +1 -0
- package/payload/platform/plugins/whatsapp/mcp/dist/__tests__/format-login-start.test.js +16 -0
- package/payload/platform/plugins/whatsapp/mcp/dist/__tests__/format-login-start.test.js.map +1 -0
- package/payload/platform/plugins/whatsapp/mcp/dist/format.d.ts +7 -0
- package/payload/platform/plugins/whatsapp/mcp/dist/format.d.ts.map +1 -0
- package/payload/platform/plugins/whatsapp/mcp/dist/format.js +21 -0
- package/payload/platform/plugins/whatsapp/mcp/dist/format.js.map +1 -0
- package/payload/platform/plugins/whatsapp/mcp/dist/index.js +11 -19
- package/payload/platform/plugins/whatsapp/mcp/dist/index.js.map +1 -1
- package/payload/platform/plugins/whatsapp/references/channels-whatsapp.md +1 -1
- package/payload/platform/plugins/whatsapp/skills/connect-whatsapp/SKILL.md +15 -13
- package/payload/platform/plugins/x-import/.claude-plugin/plugin.json +1 -1
- package/payload/platform/plugins/x-import/PLUGIN.md +2 -2
- package/payload/platform/scripts/check-skill-frontmatter.mjs +8 -5
- package/payload/platform/scripts/wifi-provision-server/server.js +1 -1
- package/payload/platform/scripts/wifi-provision.sh +1 -1
- package/payload/platform/services/claude-session-manager/dist/canonical-tool-names.generated.d.ts.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/canonical-tool-names.generated.js +1 -0
- package/payload/platform/services/claude-session-manager/dist/canonical-tool-names.generated.js.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/pty-spawner.d.ts.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/pty-spawner.js +15 -15
- package/payload/platform/services/claude-session-manager/dist/pty-spawner.js.map +1 -1
- package/payload/platform/templates/agents/admin/IDENTITY.md +3 -3
- package/payload/platform/templates/specialists/.claude-plugin/plugin.json +1 -1
- package/payload/premium-plugins/venture-studio/skills/prototype-host/SKILL.md +1 -1
- package/payload/server/{adminuser-self-heal-YC47O34W.js → adminuser-self-heal-LC7HZAC6.js} +17 -9
- package/payload/server/{chunk-HYQNUVGO.js → chunk-PFF6I7KP.js} +1 -8
- package/payload/server/{chunk-ET3BKHKR.js → chunk-SOLVVUST.js} +11 -3
- package/payload/server/maxy-edge.js +2 -2
- package/payload/server/public/assets/{AdminShell-8JLQM1Mz.js → AdminShell-BcHJy_Y2.js} +1 -1
- package/payload/server/public/assets/{Checkbox-CuFJh7lI.js → Checkbox-BY2lndUH.js} +1 -1
- package/payload/server/public/assets/{admin-D4nsdmKU.js → admin-C364q_-g.js} +1 -1
- package/payload/server/public/assets/{architectureDiagram-Q4EWVU46-D-ODjJS5.js → architectureDiagram-Q4EWVU46-B9ik0JyO.js} +1 -1
- package/payload/server/public/assets/{blockDiagram-DXYQGD6D-DFuVe8f9.js → blockDiagram-DXYQGD6D-C-w-AMRJ.js} +1 -1
- package/payload/server/public/assets/{browser-DIKmvDl5.js → browser-D66JrDpx.js} +1 -1
- package/payload/server/public/assets/{c4Diagram-AHTNJAMY-CeVLfznT.js → c4Diagram-AHTNJAMY-BH-b0NZ1.js} +1 -1
- package/payload/server/public/assets/channel-5xoW3jfU.js +1 -0
- package/payload/server/public/assets/{chunk-336JU56O-BTaLfR3a.js → chunk-336JU56O-CZHLbmJj.js} +2 -2
- package/payload/server/public/assets/{chunk-426QAEUC-BzTbm4pP.js → chunk-426QAEUC-Qx6Ggp9s.js} +1 -1
- package/payload/server/public/assets/{chunk-4TB4RGXK-SiUyOXVG.js → chunk-4TB4RGXK-J1Raz9l0.js} +1 -1
- package/payload/server/public/assets/{chunk-5FUZZQ4R-BcQ33LnT.js → chunk-5FUZZQ4R-D6TFnJVF.js} +1 -1
- package/payload/server/public/assets/{chunk-5PVQY5BW-CT7C1Tik.js → chunk-5PVQY5BW-CC5aEdzK.js} +1 -1
- package/payload/server/public/assets/{chunk-EDXVE4YY-CK3uI2u6.js → chunk-EDXVE4YY-Bfbcdcbt.js} +1 -1
- package/payload/server/public/assets/{chunk-ENJZ2VHE-Ddp8Otnw.js → chunk-ENJZ2VHE-7EKi84Dw.js} +1 -1
- package/payload/server/public/assets/{chunk-ICPOFSXX-DHTxymk_.js → chunk-ICPOFSXX-DIH1FT8n.js} +1 -1
- package/payload/server/public/assets/{chunk-OYMX7WX6-Heg3hegz.js → chunk-OYMX7WX6-MgP02n7p.js} +1 -1
- package/payload/server/public/assets/{chunk-U2HBQHQK-Cw2PR7aJ.js → chunk-U2HBQHQK-Cwmbq3M7.js} +1 -1
- package/payload/server/public/assets/{chunk-X2U36JSP-C7vBCAQQ.js → chunk-X2U36JSP-D65N3MkW.js} +1 -1
- package/payload/server/public/assets/{chunk-YZCP3GAM-BS8Mybh1.js → chunk-YZCP3GAM-BkCiRhSG.js} +1 -1
- package/payload/server/public/assets/{chunk-ZZ45TVLE-DmnbQp47.js → chunk-ZZ45TVLE-3BQY1FWN.js} +1 -1
- package/payload/server/public/assets/classDiagram-6PBFFD2Q-DRSNlIL5.js +1 -0
- package/payload/server/public/assets/classDiagram-v2-HSJHXN6E-CYvRRfMp.js +1 -0
- package/payload/server/public/assets/clone-DvQUt_lq.js +1 -0
- package/payload/server/public/assets/{dagre-D4i6r8zi.js → dagre-DVhW13RD.js} +1 -1
- package/payload/server/public/assets/{dagre-KV5264BT-znWS6Wh2.js → dagre-KV5264BT-CtfjEgDz.js} +1 -1
- package/payload/server/public/assets/{data-CHqF4bkS.js → data-uiOcPh8T.js} +1 -1
- package/payload/server/public/assets/{diagram-5BDNPKRD-B6tQBN1Y.js → diagram-5BDNPKRD-C8AXEFch.js} +1 -1
- package/payload/server/public/assets/{diagram-G4DWMVQ6-t73WpYIY.js → diagram-G4DWMVQ6-B1P8Cwuz.js} +1 -1
- package/payload/server/public/assets/{diagram-MMDJMWI5-Cm63UOJm.js → diagram-MMDJMWI5-QBVBnPmO.js} +1 -1
- package/payload/server/public/assets/{diagram-TYMM5635-DuTSLjVB.js → diagram-TYMM5635-D2xE8fN8.js} +1 -1
- package/payload/server/public/assets/{erDiagram-SMLLAGMA-sbHunitX.js → erDiagram-SMLLAGMA-DMee1Yih.js} +1 -1
- package/payload/server/public/assets/{flowDiagram-DWJPFMVM-BWOrPuqz.js → flowDiagram-DWJPFMVM-DAd3JjoB.js} +1 -1
- package/payload/server/public/assets/{ganttDiagram-T4ZO3ILL-WaLMGard.js → ganttDiagram-T4ZO3ILL-Bs33CmKo.js} +1 -1
- package/payload/server/public/assets/{gitGraphDiagram-UUTBAWPF-CsbIgKDn.js → gitGraphDiagram-UUTBAWPF-NXc8aeps.js} +1 -1
- package/payload/server/public/assets/{graph-kwyPyf_b.js → graph-BSHyF267.js} +1 -1
- package/payload/server/public/assets/{graph-labels-pX3uIQys.js → graph-labels-D5ecmK-Z.js} +1 -1
- package/payload/server/public/assets/{graphlib-B8yKFZvc.js → graphlib-DN7sm5nK.js} +1 -1
- package/payload/server/public/assets/{infoDiagram-42DDH7IO-Bd55TzsD.js → infoDiagram-42DDH7IO-D2g5STFr.js} +1 -1
- package/payload/server/public/assets/{ishikawaDiagram-UXIWVN3A-BFdOsA9f.js → ishikawaDiagram-UXIWVN3A-DBgfV-LB.js} +1 -1
- package/payload/server/public/assets/{journeyDiagram-VCZTEJTY-CMQ5XWO9.js → journeyDiagram-VCZTEJTY-Chh9lW9P.js} +1 -1
- package/payload/server/public/assets/{kanban-definition-6JOO6SKY-_RpNNRN7.js → kanban-definition-6JOO6SKY-buI2AXpi.js} +1 -1
- package/payload/server/public/assets/{line-SkFxjGJ8.js → line-C8OFYjrW.js} +1 -1
- package/payload/server/public/assets/{mermaid-parser.core-Ddok2IAe.js → mermaid-parser.core-BI5Ythbv.js} +1 -1
- package/payload/server/public/assets/{mermaid.core-CihAjXBG.js → mermaid.core-C4dyl1Xw.js} +3 -3
- package/payload/server/public/assets/{mindmap-definition-QFDTVHPH-CJsq3hrO.js → mindmap-definition-QFDTVHPH-BbXKSpiv.js} +1 -1
- package/payload/server/public/assets/{pieDiagram-DEJITSTG-CSgg8lBB.js → pieDiagram-DEJITSTG-C8-OIoUW.js} +1 -1
- package/payload/server/public/assets/{public-BA9P-3ZV.js → public-DGlZwbyw.js} +3 -3
- package/payload/server/public/assets/{quadrantDiagram-34T5L4WZ-TtHxMQtS.js → quadrantDiagram-34T5L4WZ-HOEtpu4n.js} +1 -1
- package/payload/server/public/assets/{requirementDiagram-MS252O5E-DdYupKtL.js → requirementDiagram-MS252O5E-DLxjohCO.js} +1 -1
- package/payload/server/public/assets/{sankeyDiagram-XADWPNL6-BVfdyUnO.js → sankeyDiagram-XADWPNL6-E_O_HiFL.js} +1 -1
- package/payload/server/public/assets/{sequenceDiagram-FGHM5R23-aFLOua6n.js → sequenceDiagram-FGHM5R23-C3-hhAup.js} +1 -1
- package/payload/server/public/assets/{stateDiagram-FHFEXIEX-_3Ix8SPZ.js → stateDiagram-FHFEXIEX-BhAmQ0XX.js} +1 -1
- package/payload/server/public/assets/stateDiagram-v2-QKLJ7IA2-Dhrf9hq_.js +1 -0
- package/payload/server/public/assets/{timeline-definition-GMOUNBTQ-Bs96WqZ7.js → timeline-definition-GMOUNBTQ-DpfZt7xI.js} +1 -1
- package/payload/server/public/assets/{useSelectionMode-L9uAHstA.css → useSelectionMode-98jrB9kD.css} +1 -1
- package/payload/server/public/assets/{vennDiagram-DHZGUBPP-DE_SxsN2.js → vennDiagram-DHZGUBPP-Ck2Ago5q.js} +1 -1
- package/payload/server/public/assets/{wardleyDiagram-NUSXRM2D-DTCdKs6v.js → wardleyDiagram-NUSXRM2D-Dgk8C9kF.js} +1 -1
- package/payload/server/public/assets/{xychartDiagram-5P7HB3ND-CNIrxADs.js → xychartDiagram-5P7HB3ND-BRBSl8ID.js} +1 -1
- package/payload/server/public/browser.html +4 -4
- package/payload/server/public/data.html +5 -5
- package/payload/server/public/graph.html +6 -6
- package/payload/server/public/index.html +5 -5
- package/payload/server/public/public.html +4 -4
- package/payload/server/server.js +607 -5064
- package/payload/server/public/assets/channel-Db8J_1Rl.js +0 -1
- package/payload/server/public/assets/classDiagram-6PBFFD2Q-DjquNGFr.js +0 -1
- package/payload/server/public/assets/classDiagram-v2-HSJHXN6E-CcE8sWEP.js +0 -1
- package/payload/server/public/assets/clone-xa7JZYoY.js +0 -1
- package/payload/server/public/assets/stateDiagram-v2-QKLJ7IA2-eVQQEyxx.js +0 -1
- /package/payload/server/public/assets/{useSelectionMode-Da9Glxvu.js → useSelectionMode-80iYuGPa.js} +0 -0
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: platform-architecture
|
|
3
3
|
description: Use when grounding any documented-surface claim about what SiteOffice ships — plugins, skills, specialists, install/deploy flows, internals. This is the install catalogue, not evidence of what is enabled on the current account. For install state on this account, call `capabilities-here`; for documented surface, cite the `Source:` URL inline.
|
|
4
|
-
content-hash: sha256:
|
|
4
|
+
content-hash: sha256:4689ef665b110bf635cf207902292849ab66cb6af548410fe5b49f1364c64d86
|
|
5
5
|
brand: siteoffice-code
|
|
6
6
|
product-name: SiteOffice
|
|
7
7
|
---
|
|
@@ -15,27 +15,27 @@ This skill is generated. Its body is the concatenated source markdown for every
|
|
|
15
15
|
When you load this skill to ground a factual claim, cite the `Source:` URL printed above the block you drew from. The URL is the canonical public docs page (https://siteoffice.online); relay it as a markdown link in your reply. Training-data recall is not a permitted source — the body below is.
|
|
16
16
|
|
|
17
17
|
---
|
|
18
|
-
#
|
|
18
|
+
# SiteOffice Documentation — full corpus
|
|
19
19
|
|
|
20
|
-
Concatenated source markdown for every public
|
|
20
|
+
Concatenated source markdown for every public SiteOffice docs page. Pages are separated by `---` and labelled with their canonical URL.
|
|
21
21
|
|
|
22
22
|
---
|
|
23
23
|
# Getting Started
|
|
24
24
|
Source: https://docs.getmaxy.com/getting-started.md
|
|
25
25
|
|
|
26
|
-
# Getting Started with
|
|
26
|
+
# Getting Started with SiteOffice
|
|
27
27
|
|
|
28
|
-
## What
|
|
28
|
+
## What SiteOffice Is
|
|
29
29
|
|
|
30
|
-
|
|
30
|
+
SiteOffice is your Operations Manager — an operations layer that runs on a device on your premises. It plays four roles: follows through on your commitments, responds to your customers at any hour, handles your finances (quotes, invoices, chasing), and manages your picture — what's overdue, what's at risk, what needs a decision.
|
|
31
31
|
|
|
32
|
-
You don't adopt a new system. You just talk, and the organisation happens.
|
|
32
|
+
You don't adopt a new system. You just talk, and the organisation happens. SiteOffice connects to your services — WhatsApp, Telegram, email, your contacts, your calendar — and acts proactively. It remembers context across conversations and takes action on your behalf.
|
|
33
33
|
|
|
34
|
-
Because
|
|
34
|
+
Because SiteOffice runs locally, your data stays in your home. It never passes through someone else's cloud.
|
|
35
35
|
|
|
36
36
|
## The Two Interfaces
|
|
37
37
|
|
|
38
|
-
**Admin (you)** — accessed at your local address (e.g. `maxy.local:19200`) or remotely via your Cloudflare domain. The admin interface is protected by a PIN. This is where you manage
|
|
38
|
+
**Admin (you)** — accessed at your local address (e.g. `maxy.local:19200`) or remotely via your Cloudflare domain. The admin interface is protected by a PIN. This is where you manage SiteOffice: configure settings, manage contacts, review activity, and have full conversations. The admin agent has access to all your plugins and can take action.
|
|
39
39
|
|
|
40
40
|
**Public (visitors)** — anyone who reaches your public URL gets the public agent. It handles product enquiries, collects prospect details, and answers questions about your business. It cannot read or write your private data.
|
|
41
41
|
|
|
@@ -44,7 +44,7 @@ Because Maxy runs locally, your data stays in your home. It never passes through
|
|
|
44
44
|
If your device has no WiFi configured and no ethernet cable connected, it creates a temporary WiFi network for setup:
|
|
45
45
|
|
|
46
46
|
1. Power on the device and wait about 60 seconds
|
|
47
|
-
2. On your phone, look for a WiFi network called **{ProductName}-Setup** (e.g. `
|
|
47
|
+
2. On your phone, look for a WiFi network called **{ProductName}-Setup** (e.g. `SiteOffice-Setup`)
|
|
48
48
|
3. Connect to that network — a setup page opens automatically
|
|
49
49
|
4. Select your home WiFi network from the list and enter the password
|
|
50
50
|
5. The device connects to your WiFi and the temporary network disappears
|
|
@@ -59,15 +59,15 @@ If you already have ethernet connected, the temporary WiFi network does not appe
|
|
|
59
59
|
When you first open the admin interface:
|
|
60
60
|
|
|
61
61
|
1. Set your PIN — this protects access to the admin interface
|
|
62
|
-
2. Connect to Claude —
|
|
62
|
+
2. Connect to Claude — SiteOffice will guide you through connecting to your Claude account
|
|
63
63
|
3. Enter your PIN to log in
|
|
64
|
-
4.
|
|
64
|
+
4. SiteOffice walks you through onboarding: choosing which plugins to activate, connecting to WiFi (skip if already configured via the setup network above), setting up remote access, and configuring your account
|
|
65
65
|
|
|
66
|
-
This setup is resumable — if you close the browser mid-setup,
|
|
66
|
+
This setup is resumable — if you close the browser mid-setup, SiteOffice picks up where you left off next time.
|
|
67
67
|
|
|
68
68
|
After install, a live admin terminal is available inside the Software Update window — your Pi's shell, accessible through the admin UI, for upgrades and any other shell work without needing to SSH.
|
|
69
69
|
|
|
70
|
-
## How to Use
|
|
70
|
+
## How to Use SiteOffice
|
|
71
71
|
|
|
72
72
|
Conversation is the only interface. Type or speak what you need:
|
|
73
73
|
|
|
@@ -77,23 +77,23 @@ Conversation is the only interface. Type or speak what you need:
|
|
|
77
77
|
- "Send a Telegram message to the team: standup in 10 minutes"
|
|
78
78
|
- "Create a one-pager PDF about our new product launch"
|
|
79
79
|
|
|
80
|
-
|
|
80
|
+
SiteOffice understands plain language. You don't need to learn commands or navigate menus.
|
|
81
81
|
|
|
82
82
|
### Voice Notes
|
|
83
83
|
|
|
84
|
-
When the text field is empty, a microphone button appears in place of the send button. Tap it to record a voice note — speak naturally and tap send when done.
|
|
84
|
+
When the text field is empty, a microphone button appears in place of the send button. Tap it to record a voice note — speak naturally and tap send when done. SiteOffice transcribes your voice note and responds to what you said, the same as if you had typed it. You can also pause and resume recording, or tap the trash icon to discard and start over.
|
|
85
85
|
|
|
86
|
-
Voice recording requires a secure connection (HTTPS). When accessing
|
|
86
|
+
Voice recording requires a secure connection (HTTPS). When accessing SiteOffice over the local network via HTTP, use the tunnel URL for voice notes.
|
|
87
87
|
|
|
88
|
-
You can also drop, paste, or pick an audio file (`.opus`, `.ogg`, `.m4a`, `.mp3`, `.wav`, `.webm`) into the chat composer — for example a voice note forwarded from WhatsApp. The file is transcribed the same way the in-browser recording is, and only the transcript reaches
|
|
88
|
+
You can also drop, paste, or pick an audio file (`.opus`, `.ogg`, `.m4a`, `.mp3`, `.wav`, `.webm`) into the chat composer — for example a voice note forwarded from WhatsApp. The file is transcribed the same way the in-browser recording is, and only the transcript reaches SiteOffice; the audio itself is discarded after transcription.
|
|
89
89
|
|
|
90
|
-
## What
|
|
90
|
+
## What SiteOffice Remembers
|
|
91
91
|
|
|
92
|
-
|
|
92
|
+
SiteOffice maintains a memory graph of everything important: contacts, conversations, preferences, relationships, and context. When you tell SiteOffice something, it stores it. When you ask about something later, it retrieves it.
|
|
93
93
|
|
|
94
|
-
You can always tell
|
|
94
|
+
You can always tell SiteOffice to remember or forget specific things: "Remember that I prefer morning calls" or "Forget what I said about the Johnson account."
|
|
95
95
|
|
|
96
|
-
## Reaching Your Data When
|
|
96
|
+
## Reaching Your Data When SiteOffice Is Unavailable
|
|
97
97
|
|
|
98
98
|
If the AI is ever unreachable — network outage, API provider down — you can still access your own data through the **Data** item in the admin header menu. It opens a page with two panels:
|
|
99
99
|
|
|
@@ -104,21 +104,21 @@ Everything on this page works without calling any AI service. It's there so your
|
|
|
104
104
|
|
|
105
105
|
## Getting Help
|
|
106
106
|
|
|
107
|
-
Ask
|
|
107
|
+
Ask SiteOffice anything. If you want to know what it can do, just ask: "What can you help me with?" or "How do I set up Telegram?"
|
|
108
108
|
|
|
109
109
|
---
|
|
110
|
-
# How
|
|
110
|
+
# How SiteOffice Works
|
|
111
111
|
Source: https://docs.getmaxy.com/platform.md
|
|
112
112
|
|
|
113
|
-
# How
|
|
113
|
+
# How SiteOffice Works
|
|
114
114
|
|
|
115
115
|
## The Short Version
|
|
116
116
|
|
|
117
|
-
|
|
117
|
+
SiteOffice runs on a Raspberry Pi in your home. It uses Claude (Anthropic's AI) as its brain and extends it with plugins — modular capabilities like contacts, Telegram, and memory. Everything stays local: your data, your conversations, your memory graph.
|
|
118
118
|
|
|
119
119
|
## The Raspberry Pi
|
|
120
120
|
|
|
121
|
-
|
|
121
|
+
SiteOffice is a server that lives on your local network. It's always on, always available, and accessible:
|
|
122
122
|
|
|
123
123
|
- **Locally:** `maxy.local:19200` (or the IP address of your Pi)
|
|
124
124
|
- **Remotely:** via your personal domain, routed through a Cloudflare tunnel
|
|
@@ -127,7 +127,7 @@ The Pi runs the web interface, the AI agent, and all the plugin servers. When yo
|
|
|
127
127
|
|
|
128
128
|
## The Two Agents
|
|
129
129
|
|
|
130
|
-
|
|
130
|
+
SiteOffice runs two agents simultaneously:
|
|
131
131
|
|
|
132
132
|
**Admin agent (you)** — full access to all tools and plugins. This is the agent you interact with at your local or remote URL. It can read and write contacts, send Telegram messages, manage your account, and perform any task you have plugins for. Protected by your PIN. Your admin agent runs through your own Claude Code OAuth session — it never bills the Anthropic API. Authentication and SDK details are documented in the developer doc `.docs/platform.md` admin-agent section.
|
|
133
133
|
|
|
@@ -135,7 +135,7 @@ Maxy runs two agents simultaneously:
|
|
|
135
135
|
|
|
136
136
|
## Plugins
|
|
137
137
|
|
|
138
|
-
Everything
|
|
138
|
+
Everything SiteOffice can do is provided by a plugin. Each plugin is a self-contained package:
|
|
139
139
|
|
|
140
140
|
- Behaviour instructions (how the agent should act)
|
|
141
141
|
- Tools (specific actions the agent can take, exposed via MCP servers)
|
|
@@ -145,13 +145,13 @@ Everything Maxy can do is provided by a plugin. Each plugin is a self-contained
|
|
|
145
145
|
|
|
146
146
|
**Where premium bundle subs live.** Bundle subs (`loop`, `property-data`, `brochures`, etc. inside `real-agent`) live exclusively at `premium-plugins/<bundle>/plugins/<sub>/` and are registered via the resolver's bundle-descent walk. Standalone premiums (no `BUNDLE.md`, e.g. `writer-craft`, `teaching`, `venture-studio`) live exclusively at `premium-plugins/<name>/` and are registered via the resolver's dual-root scan (`platform/plugins/` and `premium-plugins/` are both `pluginsRoots`). Neither shape is flat-copied into `platform/plugins/<name>/`. A divergent flat copy of a bundle sub is treated as an operator override: the resolver refuses to boot with `boot-failed reason=mcp-plugin-duplicate <plugin> declared by more than one plugins root: <pathA> (sha=…) vs <pathB> (sha=…)` so the operator can `sha256sum` both paths and remove the stale one. Byte-identical bundle-sub flat copies left over from installer versions that flat-copied bundle subs are reaped on the first post-upgrade boot (`[premium-auto-deliver] reaped sub=<name> reason=duplicate-of-premium-tree`). Standalone flat copies (leaked by the pre-fix `autoDeliverPremiumPlugins` standalone branch) are reaped unconditionally — there is no documented override path for standalones at `platform/plugins/<name>/` — and the reaper logs `[premium-auto-deliver] reaped standalone=<name> matches-source=<true|false>` so divergent reaps leave a forensic trail.
|
|
147
147
|
|
|
148
|
-
Plugins are installed and managed through conversation. You can add marketplace plugins (like Stripe) or use
|
|
148
|
+
Plugins are installed and managed through conversation. You can add marketplace plugins (like Stripe) or use SiteOffice's built-in ones (contacts, memory, Telegram).
|
|
149
149
|
|
|
150
150
|
## Roles
|
|
151
151
|
|
|
152
|
-
|
|
152
|
+
SiteOffice ships twelve roles it can dispatch for specific tasks — like members of your team. You don't need to configure or manage them — SiteOffice decides when to use each role and handles everything automatically. You may see activity like "Dispatching personal-assistant..." in the chat timeline when this happens.
|
|
153
153
|
|
|
154
|
-
The catalogue below is what the platform ships. It is not evidence of what is installed on the current account. For the live install set on this account, ask
|
|
154
|
+
The catalogue below is what the platform ships. It is not evidence of what is installed on the current account. For the live install set on this account, ask SiteOffice to call `capabilities-here`.
|
|
155
155
|
|
|
156
156
|
| Role | What it does |
|
|
157
157
|
|------|-------------|
|
|
@@ -168,13 +168,13 @@ The catalogue below is what the platform ships. It is not evidence of what is in
|
|
|
168
168
|
| Research Assistant | Researches topics online, manages your knowledge graph, and produces supporting visuals. |
|
|
169
169
|
| Typed Edge Classifier | Reads recently-written prose nodes and writes typed edges from a closed allowlist. |
|
|
170
170
|
|
|
171
|
-
Roles are installed during setup and listed when
|
|
171
|
+
Roles are installed during setup and listed when SiteOffice introduces itself. Some premium bundles add their own specialists (e.g. the `real-agent` bundle adds a listing curator, negotiator, valuer, compliance officer, and buyer-enquiry public agent). Roles installed mid-session become active from the next session.
|
|
172
172
|
|
|
173
173
|
## Memory
|
|
174
174
|
|
|
175
|
-
|
|
175
|
+
SiteOffice maintains a graph database (Neo4j) of everything you've told it. People, conversations, preferences, and context are stored as connected nodes. When you ask SiteOffice something, it searches this graph to retrieve relevant context before responding.
|
|
176
176
|
|
|
177
|
-
**The recording loop.**
|
|
177
|
+
**The recording loop.** SiteOffice dispatches `database-operator` inline at its own discretion when a write must complete before the assistant response ends. The full graph-completeness sweep runs on demand: when you invoke the `/insight` admin skill, it runs a four-pass instruction and SiteOffice walks the session for any node, edge, or commitment that was discussed but not written in-flight, dispatches one `database-operator` Task per candidate write, then carries on in the same session.
|
|
178
178
|
|
|
179
179
|
The memory graph is stored on your Pi. It never leaves your network.
|
|
180
180
|
|
|
@@ -192,9 +192,9 @@ There is no dashboard, no settings panel, no menus. Everything is done through c
|
|
|
192
192
|
|
|
193
193
|
The chat input auto-grows as you type — it expands to fit your message and shrinks back when you delete text. You can also drag the resize handle above the input to set a custom height.
|
|
194
194
|
|
|
195
|
-
The admin interface is a three-pane layout: a sidebar on the left with navigation (Sessions, People, Agents, Projects, Tasks, Artefacts) and your recent conversations; the chat in the middle; and an artefact pane on the right that opens when you select a document, click a project, or open Browser, Data, or Graph from the menu, holding the surface side-by-side with the conversation so the chat stays live while you work in it. At the very top of the sidebar — above the nav rows — a borderless row holds two controls: a "+ New session" button on the left that spawns a fresh Claude Code session, and a Mode trigger on the right showing the current permission mode (Ask, Accept edits, Plan, or Auto). The sidebar's vertical order is: new-session strip first, then the nav (Sessions, People, Agents, Projects, Tasks, Artefacts), then the sessions list, then the footer. Both controls render as plain text-plus-icon affordances with no surrounding rectangle. The "+ New session" button is a text-width hit target — its clickable area is exactly the icon plus label, not the whole row — and shows no hover fill; the only hover feedback is the pointer cursor. The Mode trigger is pushed flush to the right edge of the row. Clicking the Mode trigger opens a popover downward from the row whose header reads "Mode" and lists the four permission modes with the current selection check-marked. The sidebar's nav rows swap the list view in place: Sessions shows recent conversations, Projects shows your active work projects, and Artefacts lists every KnowledgeDocument plus this account's agent templates (your admin agent's IDENTITY, SOUL, and KNOWLEDGE files plus one entry per enabled specialist). Each recent session row carries a three-state indicator: three pulsing dots when the session is busy (currently processing a turn), a solid sage dot when it is idle (live PTY waiting for input), and a hollow ring when it is archived (PTY exited, JSONL on disk for audit). The list itself splits into three views via a segmented control above the rows: **Active** shows every live session, **Archived** shows every JSONL on disk whose PTY has exited, and **All** shows both. The view choice persists across reloads. An "Include subagents" toggle inside the Active view surfaces specialist spawns (database-operator, premium-plugin agents, anything spawned with a `--agent` flag) which are hidden by default so the list reflects what you started directly. Each row also carries a small uppercase badge — `admin` for operator-driven sessions, the specialist name (for example `db-op`) for background work — so the source of any row is unambiguous at a glance. The People, Agents, and Tasks rows are graph shortcuts: clicking each opens the artefact-pane Graph filtered to every Person, every public Agent, or every Task in your account respectively, with no side-list, because the graph itself is the result. Public agents become first-class graph entities the moment you create them, with edges to their IDENTITY/SOUL/KNOWLEDGE files, edges to every knowledge document they have access to, and edges from every conversation they have handled, so a single Agents click reveals the whole shape of who knows what and who has been talking to whom. Click an artefact row to open the document. KnowledgeDocuments and your admin agent's templates are editable: type in the document and changes save automatically; specialist agent templates are read-only because they ship with
|
|
195
|
+
The admin interface is a three-pane layout: a sidebar on the left with navigation (Sessions, People, Agents, Projects, Tasks, Artefacts) and your recent conversations; the chat in the middle; and an artefact pane on the right that opens when you select a document, click a project, or open Browser, Data, or Graph from the menu, holding the surface side-by-side with the conversation so the chat stays live while you work in it. At the very top of the sidebar — above the nav rows — a borderless row holds two controls: a "+ New session" button on the left that spawns a fresh Claude Code session, and a Mode trigger on the right showing the current permission mode (Ask, Accept edits, Plan, or Auto). The sidebar's vertical order is: new-session strip first, then the nav (Sessions, People, Agents, Projects, Tasks, Artefacts), then the sessions list, then the footer. Both controls render as plain text-plus-icon affordances with no surrounding rectangle. The "+ New session" button is a text-width hit target — its clickable area is exactly the icon plus label, not the whole row — and shows no hover fill; the only hover feedback is the pointer cursor. The Mode trigger is pushed flush to the right edge of the row. Clicking the Mode trigger opens a popover downward from the row whose header reads "Mode" and lists the four permission modes with the current selection check-marked. The sidebar's nav rows swap the list view in place: Sessions shows recent conversations, Projects shows your active work projects, and Artefacts lists every KnowledgeDocument plus this account's agent templates (your admin agent's IDENTITY, SOUL, and KNOWLEDGE files plus one entry per enabled specialist). Each recent session row carries a three-state indicator: three pulsing dots when the session is busy (currently processing a turn), a solid sage dot when it is idle (live PTY waiting for input), and a hollow ring when it is archived (PTY exited, JSONL on disk for audit). The list itself splits into three views via a segmented control above the rows: **Active** shows every live session, **Archived** shows every JSONL on disk whose PTY has exited, and **All** shows both. The view choice persists across reloads. An "Include subagents" toggle inside the Active view surfaces specialist spawns (database-operator, premium-plugin agents, anything spawned with a `--agent` flag) which are hidden by default so the list reflects what you started directly. Each row also carries a small uppercase badge — `admin` for operator-driven sessions, the specialist name (for example `db-op`) for background work — so the source of any row is unambiguous at a glance. The People, Agents, and Tasks rows are graph shortcuts: clicking each opens the artefact-pane Graph filtered to every Person, every public Agent, or every Task in your account respectively, with no side-list, because the graph itself is the result. Public agents become first-class graph entities the moment you create them, with edges to their IDENTITY/SOUL/KNOWLEDGE files, edges to every knowledge document they have access to, and edges from every conversation they have handled, so a single Agents click reveals the whole shape of who knows what and who has been talking to whom. Click an artefact row to open the document. KnowledgeDocuments and your admin agent's templates are editable: type in the document and changes save automatically; specialist agent templates are read-only because they ship with SiteOffice and your edits would be overwritten on the next install. PDF artefacts render inline so you can read them without leaving the pane. If your browser doesn't have a built-in PDF viewer, a Download button appears instead. Artefacts that have no readable file backing them (orphan rows, files removed from disk, unsupported content types) show a one-line banner explaining the skip instead of opening to a blank pane. Click a project row to open the Graph view focused on that project's neighbourhood; clicking a second project swaps the focus rather than stacking on top. The sidebar's right edge is drag-resizable on every admin page (Sessions root, Graph, and Data): drag the handle to widen or narrow the sidebar, and your chosen width is remembered across reloads and shared across all three pages. The drag handle is mounted by each AdminShell consumer rather than by AdminShell itself, so any new admin route must include `<SidebarSplitter />` as a direct child of its `<AdminShell>` to pick up the shared width. The chat and artefact divider is also drag-resizable: drag the line between the columns to make either side wider; double-click it to reset to half of the available width (viewport minus sidebar), clamped to the chat and artefact min-width floors. Your chosen width is remembered across reloads. On wider screens (>1280px) all three panes are visible. The sidebar narrows at 1280px, the artefact pane hides at 1080px (Browser, Data, and Graph then open as full-window pages instead), and the sidebar collapses to a 56px icon rail at 820px. On every viewport the chat header reads left to right as a triptych: a dedicated sidebar toggle (the panel-right icon, which swaps to panel-right-open when the sidebar is showing), the brand mark next to the title in the centre, and the menu burger on the right. This header toggle is the sole sidebar-toggle button; the sidebar itself no longer carries a duplicate. Tap the sidebar toggle to show or hide the sidebar: on phones (<720px) it slides the drawer in or out, on wider screens it collapses or expands the sidebar column. The brand mark in the centre is decorative; clicks go through the dedicated toggle so the affordance is unambiguous. The drawer animation only fires on tap (220ms slide in or out); resizing your window across the 720px boundary snaps the layout without animation, so you never see a half-open flash. At ≤640px the session metadata pane stacks each label above its value instead of the desktop two-column grid, and the row of action buttons (Open in new tab / Download JSONL / View JSONL / Rename / Pin / Archive / End or Purge) collapses behind a single Actions trigger that opens a popover upward from the foot of the pane. Breakpoint summary: >1280px = full sidebar + chat + artefact pane (drag-resizable divider); 1280px→1080px = sidebar narrows; 1080px→820px = artefact pane hides (Browser/Data/Graph open as full-window pages instead); 820px→720px = sidebar collapses to 56px icon rail; ≤720px = sidebar becomes off-canvas drawer (vertical stack of nav, recents list, foot, the same shape as the desktop sidebar, just on top of the chat instead of beside it).
|
|
196
196
|
|
|
197
|
-
Page titles are brand-aware: the browser tab shows your product name (e.g. `Real Agent` instead of `
|
|
197
|
+
Page titles are brand-aware: the browser tab shows your product name (e.g. `Real Agent` instead of `SiteOffice`) on every shell — chat, graph, and data — so a non-default brand never leaks the default name in tab strips or browser history.
|
|
198
198
|
|
|
199
199
|
**Session lifecycle and reconcile model.** The sidebar Sessions list is driven by a single Server-Sent Events feed at `/api/admin/claude-sessions/events`. The session manager watches the two directories Claude Code writes (`${CLAUDE_CONFIG_DIR}/sessions/<pid>.json` for live state, `${CLAUDE_CONFIG_DIR}/projects/<slug>/<sid>.jsonl` for transcripts) and emits `row-created`, `row-updated`, `row-archived`, or `row-removed` deltas to every connected browser tab. Three real delete shapes map to deltas — there is no fourth: PID file gone with JSONL surviving demotes the row to `row-archived`; PID file gone with no JSONL ever written (a hidden spawn that exits before writing a JSONL) emits `row-removed` against the unindexed sessionId; a JSONL deletion against an already-unindexed row also emits `row-removed`. This branch reconciles transient hidden spawns — without it, ghost rows persist after a hidden spawn exits. On connect the manager replays the current row index so a freshly-opened tab catches up without polling, then streams deltas as files change on disk. Two open tabs see the same list within ~300ms of any spawn, status flip, or exit; no refresh button required for state to be current. The legacy `/list` fetch and `useAdminSessions` hook stay mounted to serve the ConversationsModal and the post-action reconcile path in `session-actions`, but the sidebar's visible rows come from the row store, not from `/list`. Each EventSource open emits `[admin-events] client-connected ip=<…> seeded-rows=<n>` server-side and `[admin-ui] session-row-store connected events-received=<n>` in the browser console; transport drops log `[admin-ui] session-row-store reconnect trigger=<auto|manual> attempt=<n> delay-ms=<n>` until the EventSource reattaches. The small dot at the right edge of the Active/Archived/All segmented control is the live-updates indicator: sage when the SSE feed is connected, grey when the feed has dropped. The grey state is an actionable button — clicking it cancels any pending backoff and re-opens the feed immediately, with the click logged as `trigger=manual` so manual retries are distinguishable from automatic ones in the console. The refresh icon at the top of the Sessions list is the operator-recoverable reconcile path against any SSE gap: it fetches `/api/admin/claude-sessions` and passes the authoritative id set to the row store, which evicts any indexed row that the server no longer reports. SSE replay only re-asserts currently-indexed rows and never emits `row-removed` for a row that vanished while disconnected, so without this manual surface a stale row can persist until the operator reloads the tab. Each click logs `[admin-ui] session-row-store reconcile evicted=<n> kept=<n>` when at least one row is evicted, and is silent otherwise.
|
|
200
200
|
|
|
@@ -292,7 +292,7 @@ Messages you write yourself (e.g. typing directly in WhatsApp) are not marked
|
|
|
292
292
|
|
|
293
293
|
## Session Slot Safeguards
|
|
294
294
|
|
|
295
|
-
|
|
295
|
+
SiteOffice runs each chat — yours and every visitor's — as a separate `claude` process on your Pi. Three safeguards keep these processes from piling up:
|
|
296
296
|
|
|
297
297
|
- **Specialist cap.** Background specialists (`database-operator`, `content-producer`, etc.) are limited to three running at once. If you ask for a fourth while three are still working, the oldest idle one is shut down first. If all three are actively running, the request is rejected with `specialist-cap-reached`.
|
|
298
298
|
- **Operator reserve.** Two slots are always held back for *you* — your own chats and one-off tasks. Specialist work that would consume the last reserved slot is rejected with `operator-slots-reserved`. Your interactive chats are never blocked.
|
|
@@ -314,17 +314,17 @@ Source: https://docs.getmaxy.com/plugins-guide.md
|
|
|
314
314
|
|
|
315
315
|
## What a Plugin Is
|
|
316
316
|
|
|
317
|
-
A plugin extends what
|
|
317
|
+
A plugin extends what SiteOffice can do. Each plugin adds a focused capability — contacts management, Telegram messaging, scheduling, email, research. Plugins are modular: you enable only what you need.
|
|
318
318
|
|
|
319
|
-
|
|
319
|
+
SiteOffice's own capabilities are plugins too. Marketplace plugins (like Stripe) work the same way — SiteOffice manages all of them through conversation.
|
|
320
320
|
|
|
321
|
-
The tables below are the install catalogue — every plugin the platform can ship. They are not evidence of what is enabled on the current account. For the live install set, ask
|
|
321
|
+
The tables below are the install catalogue — every plugin the platform can ship. They are not evidence of what is enabled on the current account. For the live install set, ask SiteOffice to call `capabilities-here`.
|
|
322
322
|
|
|
323
323
|
## Plugin Groups
|
|
324
324
|
|
|
325
325
|
### Core (always active)
|
|
326
326
|
|
|
327
|
-
These are part of
|
|
327
|
+
These are part of SiteOffice's foundation and cannot be disabled:
|
|
328
328
|
|
|
329
329
|
| Plugin | What it does |
|
|
330
330
|
|--------|-------------|
|
|
@@ -341,7 +341,7 @@ These are part of Maxy's foundation and cannot be disabled:
|
|
|
341
341
|
| `prompt-optimiser` | Prompt optimiser — two modes. Chat-app mode turns a rough draft or task description into a single finished, copy-pasteable prompt tuned for Opus 4.7 adaptive thinking (claude.ai, Mac, iOS). In-session mode is applied automatically: a standing `UserPromptSubmit` directive hook (`admin/hooks/prompt-optimiser-directive.sh`) injects context every turn telling the admin agent to restate each non-trivial prompt through this skill and act on the restatement, skipped for one-word confirmations, slash-commands, and direct continuations. Compliance is behavioural — the hook steers the agent, it cannot force the skill call. |
|
|
342
342
|
| `url-get` | Faithful page retrieval — fetches a server-rendered page, writes a verbatim markdown copy to an account-scoped reference file (no model in the path, so no copyright refusal), and returns the cleaned page text (capped) plus the file path. No summary and no subprocess: a caller that wants a summary invokes url-get from a delegated subagent. Use instead of WebFetch when a faithful copy is needed (e.g. ingesting your own published writing). |
|
|
343
343
|
|
|
344
|
-
###
|
|
344
|
+
### SiteOffice Plugins (user-selectable)
|
|
345
345
|
|
|
346
346
|
These are enabled during onboarding and can be added or removed at any time. Some plugins enhance a specific specialist role — when enabled, that specialist gains additional capabilities.
|
|
347
347
|
|
|
@@ -390,9 +390,9 @@ Install verbatim:
|
|
|
390
390
|
|
|
391
391
|
Brand decides which premium plugins ship. The brand's `shipsPremiumBundles` field in `brand.json` is the gate; three shapes are supported:
|
|
392
392
|
|
|
393
|
-
- **omitted / false** — ship nothing from `premium-plugins/` (the legacy
|
|
393
|
+
- **omitted / false** — ship nothing from `premium-plugins/` (the legacy SiteOffice default).
|
|
394
394
|
- **`true`** — ship every bundle under `premium-plugins/*` (Real Agent / `realagent-code`).
|
|
395
|
-
- **`["bundle-a", "bundle-b"]`** — ship only the named bundle directories (
|
|
395
|
+
- **`["bundle-a", "bundle-b"]`** — ship only the named bundle directories (SiteOffice Code's `["venture-studio"]`). Names with no matching directory on disk are silently dropped; non-allowlisted bundles are stripped from any account that was previously stamped with them.
|
|
396
396
|
|
|
397
397
|
There is no per-account purchase record; the brand decides the shipping set.
|
|
398
398
|
|
|
@@ -403,39 +403,39 @@ There is no per-account purchase record; the brand decides the shipping set.
|
|
|
403
403
|
| `writer-craft` | Skills + Agent | Manuscript review and writing craft — story architecture, reader engagement, prose craft, editorial practice, and multi-level review | No — writing craft serves the author |
|
|
404
404
|
| `venture-studio` | Skills + Agent | Founding-a-business workflow — office-hours discovery, brand pack, zero-to-prototype validation, and the full investor data room (business plan, prospectus, term sheet, deck blueprint, A4 print pipeline). Pre-seeds a `Project` with one `Task` per artefact so nothing gets forgotten. | No — founder-facing only |
|
|
405
405
|
|
|
406
|
-
**How it works:** Every boot
|
|
406
|
+
**How it works:** Every boot SiteOffice delivers the brand's premium plugins from staging into `platform/plugins/` and stamps `enabledPlugins` against what is actually on disk. No conversation needed — the brand's full set is active from the first turn after install. Updates and reinstalls re-deliver from staging.
|
|
407
407
|
|
|
408
408
|
Some premium plugins are **bundles** — multiple sub-plugins shipped under one directory in `premium-plugins/`, each independently activatable. For example, Real Agent ships 10 sub-plugins covering different aspects of estate agency work. They are all enabled by default. Sub-plugins you don't want active can be turned off individually with "disable <name>"; enabling or disabling individual sub-plugins does not affect the others.
|
|
409
409
|
|
|
410
|
-
If you ask
|
|
410
|
+
If you ask SiteOffice about a tool from a plugin your brand does not ship (for example, a SiteOffice install asking about a Real Agent Loop CRM tool), SiteOffice responds with a structured `<tool-surface-error>` envelope naming the missing plugin and the remedy, rather than improvising with a generic alternative.
|
|
411
411
|
|
|
412
412
|
**Public agent embedding:** Premium plugins marked as public-eligible have their full content (skills and reference knowledge) embedded in public agent prompts. This means a public agent for a Real Agent member can handle buyer enquiries, book viewings, deliver coaching content, and onboard new applicants — all powered by the premium plugin's domain knowledge. Plugins marked admin-only (listings, vendors, leads, business) are only available to the account owner's admin agent.
|
|
413
413
|
|
|
414
|
-
Some premium plugins include specialist helpers that
|
|
414
|
+
Some premium plugins include specialist helpers that SiteOffice can dispatch for specific tasks (e.g. the writer-craft plugin includes a manuscript reviewer). These are activated automatically when the plugin is enabled.
|
|
415
415
|
|
|
416
|
-
Some premium plugins include pre-built public agent templates — ready-made configurations for customer-facing agents. When you enable the plugin,
|
|
416
|
+
Some premium plugins include pre-built public agent templates — ready-made configurations for customer-facing agents. When you enable the plugin, SiteOffice shows you what templates are available and offers to create agents from them. You review and approve every file before the agent is created. The template is a starting point — you can edit the identity, personality, plugins, and settings to make it yours. The result is a standard public agent, indistinguishable from one you created from scratch.
|
|
417
417
|
|
|
418
418
|
Some premium plugins ship pre-built workflows that are created when the plugin is enabled. These workflows are fully yours — you can inspect, edit, run, and manage them through conversation, exactly like workflows you create yourself. The plugin provides the starting point; you own the result.
|
|
419
419
|
|
|
420
|
-
**If a premium plugin ever stops working** — `documents`, `teaching`, anything else you've paid for — and
|
|
420
|
+
**If a premium plugin ever stops working** — `documents`, `teaching`, anything else you've paid for — and SiteOffice responds as if it doesn't have those tools, the platform's health check (`/api/health.missingPlugins`) will name the affected plugin. Tell SiteOffice "deliver the {{plugin}} plugin" — it re-runs the same delivery step that fires automatically at session start. If the plugin isn't in the device's staging area, re-run the installer for this brand.
|
|
421
421
|
|
|
422
422
|
## Choosing Plugins
|
|
423
423
|
|
|
424
|
-
During first-time setup,
|
|
424
|
+
During first-time setup, SiteOffice presents a plugin selection screen where you choose which plugins to activate. Core plugins are pre-selected and locked. Recommended plugins are pre-selected but optional. You can change your mind later.
|
|
425
425
|
|
|
426
426
|
## Adding or Removing Plugins
|
|
427
427
|
|
|
428
|
-
Tell
|
|
428
|
+
Tell SiteOffice:
|
|
429
429
|
|
|
430
430
|
- "Enable the Telegram plugin"
|
|
431
431
|
- "Add the Stripe plugin"
|
|
432
432
|
- "Disable the deep-research plugin"
|
|
433
433
|
|
|
434
|
-
|
|
434
|
+
SiteOffice handles the installation or removal. If the plugin requires any setup (API keys, bot tokens, configuration), SiteOffice will walk you through it.
|
|
435
435
|
|
|
436
436
|
## Viewing Your Plugins
|
|
437
437
|
|
|
438
|
-
Ask
|
|
438
|
+
Ask SiteOffice: "What plugins do I have?" or "List my plugins."
|
|
439
439
|
|
|
440
440
|
## Operator-Authored Plugins (skill-builder output)
|
|
441
441
|
|
|
@@ -443,15 +443,15 @@ Skills you create at runtime through the admin `skill-builder` skill are saved o
|
|
|
443
443
|
|
|
444
444
|
These operator-authored plugins survive reinstall because the installer's wipe zone excludes `data/`. At admin session start the platform mirrors `data/accounts/{accountId}/plugins/*` into the runtime plugins directory so the same `parsePluginFrontmatter` / `assemblePublicPluginContent` / `loadEmbeddedPlugins` loaders that read shipped and premium plugins also pick up operator-authored ones — no special-case loader path. The admin agent sees every operator skill by default; per-skill `publicEmbed: true|false` controls which skills surface to the public agent.
|
|
445
445
|
|
|
446
|
-
To edit an operator-authored skill later, ask
|
|
446
|
+
To edit an operator-authored skill later, ask SiteOffice to update it — the admin agent re-runs `store-skill` for the same `pluginName`/`skillName` and the new content overwrites in place. To remove one, delete the directory under `data/accounts/{accountId}/plugins/{pluginName}/skills/{skillName}/` (or the whole plugin) — the next session start re-mirrors the remaining skills only.
|
|
447
447
|
|
|
448
448
|
`pluginName` collisions with shipped plugin names are refused by `store-skill` with a structured error. See [.docs/agents.md](../../../../.docs/agents.md) § "Operator-authored skills as plugin files" for the full contract.
|
|
449
449
|
|
|
450
450
|
## Brand Templating (for plugin and skill authors)
|
|
451
451
|
|
|
452
|
-
Skill content, plugin manifests, agent templates, and reference files reference the operator-visible brand name only via the literal `
|
|
452
|
+
Skill content, plugin manifests, agent templates, and reference files reference the operator-visible brand name only via the literal `SiteOffice` placeholder. The platform substitutes from `brand.json.productName` at read time — SiteOffice installs render `SiteOffice`, Real Agent installs render `Real Agent`, all from the same source content.
|
|
453
453
|
|
|
454
|
-
**Author rule:** never write the literal string `
|
|
454
|
+
**Author rule:** never write the literal string `SiteOffice` (or any brand name) in shipped skill, plugin, or template content. Use `SiteOffice` whenever the operator should see the brand name. The audit grep `grep -rn "\bMaxy\b" platform/plugins/admin/skills/ platform/plugins/*/skills/ platform/templates/agents/` must return zero matches; a literal brand name is a defect, not a stylistic choice.
|
|
455
455
|
|
|
456
456
|
The runtime substitution happens at every read site that flows content into a system prompt or operator-visible UI: the admin agent's `plugin-read` tool (references + `PLUGIN.md`), the `skill-load` tool (SKILL.md by skill name — one-call resolver+reader, the canonical primitive for SKILL.md), the public agent's recursive plugin assembly, and `IDENTITY` / `SOUL` / `AGENTS` / `KNOWLEDGE` markdown reads. Missing or empty `productName` hard-fails — there is no fallback to a default brand string. See [.docs/agents.md](../../.docs/agents.md) § "Brand templating" for the full contract.
|
|
457
457
|
|
|
@@ -472,7 +472,7 @@ After this, every `console.error("[your-tool]...")` from any tool in the plugin
|
|
|
472
472
|
|
|
473
473
|
**How the tee decides which file to write to:** the platform sets `STREAM_LOG_PATH` as an environment variable on every MCP server spawn, pointing to the conversation-scoped stream log. The MCP server does not know about conversations — it just trusts `STREAM_LOG_PATH`. Multiple concurrent conversations produce multiple concurrent MCP server processes, each teeing to its own file; no cross-conversation leakage.
|
|
474
474
|
|
|
475
|
-
**Bash commands stream straight into the PTY.**
|
|
475
|
+
**Bash commands stream straight into the PTY.** SiteOffice Code's admin and public chat run on the native Claude Code PTY (Task 287). The per-conversation server-side stream log that the retired web-UI dispatcher tailed is gone; agent-invoked Bash commands (including direct `cloudflared` invocations for Cloudflare setup — Task 288) print their stdout and stderr directly, and the PTY renders the output in chat verbatim.
|
|
476
476
|
|
|
477
477
|
**Retrieve MCP diagnostic lines for a conversation:**
|
|
478
478
|
|
|
@@ -503,9 +503,9 @@ A third layer closes the same gap from the platform side: when `claude-agent.ts`
|
|
|
503
503
|
# Install Overview
|
|
504
504
|
Source: https://docs.getmaxy.com/install.md
|
|
505
505
|
|
|
506
|
-
# Installing
|
|
506
|
+
# Installing SiteOffice Code
|
|
507
507
|
|
|
508
|
-
|
|
508
|
+
SiteOffice Code installs from one npm one-liner on every supported host. The host you choose determines the supervisor (systemd vs launchd), the Cloudflare flow (provisioned vs operator-opt-in), and the VNC requirement (Pi/cloud VM only).
|
|
509
509
|
|
|
510
510
|
| Host | Doc | Supervisor | Cloudflare tunnel | Hostname flag |
|
|
511
511
|
|---|---|---|---|---|
|
|
@@ -521,7 +521,7 @@ Engineers reading the codebase should also see [../deployment.md](../deployment.
|
|
|
521
521
|
# macOS Install
|
|
522
522
|
Source: https://docs.getmaxy.com/install/macos.md
|
|
523
523
|
|
|
524
|
-
# Installing
|
|
524
|
+
# Installing SiteOffice Code on macOS
|
|
525
525
|
|
|
526
526
|
End-to-end install for a fresh macOS account on Apple Silicon (M-series). Every command is copy-pasteable and uses auto-yes flags so nothing prompts interactively.
|
|
527
527
|
|
|
@@ -653,7 +653,7 @@ macOS is the lightweight surface. Compared with the Pi install, the macOS path d
|
|
|
653
653
|
|
|
654
654
|
The full operator-side fresh-Mac smoke is tracked separately (see `.tasks/339-macos-installer-smoke-task-297.md`). The headline pass criteria:
|
|
655
655
|
|
|
656
|
-
1. Install on a clean account with no prior
|
|
656
|
+
1. Install on a clean account with no prior SiteOffice footprint completes and prints an admin URL.
|
|
657
657
|
2. The admin UI opens at that URL and the chat surface is interactive.
|
|
658
658
|
3. Reboot — the URL is reachable again after login without any manual action.
|
|
659
659
|
4. Run `--hostname <name>` on a second install path; the URL switches to `<name>.local`.
|
|
@@ -665,7 +665,7 @@ If any step fails, attach `$HOME/.<brand>/logs/create-maxy-<timestamp>.log` to t
|
|
|
665
665
|
# Raspberry Pi Install
|
|
666
666
|
Source: https://docs.getmaxy.com/install/pi.md
|
|
667
667
|
|
|
668
|
-
# Installing
|
|
668
|
+
# Installing SiteOffice Code on a Raspberry Pi
|
|
669
669
|
|
|
670
670
|
End-to-end install for a fresh Raspberry Pi 5 (16GB) on Ubuntu Server 24.04 (64-bit). Every command is copy-pasteable and uses auto-yes flags so nothing prompts interactively. The same flow works on a Pi 4 (8GB). For a Hetzner Cloud install (CAX31 ARM64 ~€13/mo), see [hetzner.md](hetzner.md) — same installer, slightly different bootstrap for the Cloudflare tunnel because there is no LAN to the operator.
|
|
671
671
|
|
|
@@ -807,7 +807,7 @@ npx -y @rubytech/create-realagent-code@latest --uninstall
|
|
|
807
807
|
|
|
808
808
|
Fresh-Pi smoke pass criteria:
|
|
809
809
|
|
|
810
|
-
1. Install on a clean Ubuntu Server 24.04 image with no prior
|
|
810
|
+
1. Install on a clean Ubuntu Server 24.04 image with no prior SiteOffice footprint completes, prints a LAN URL, and the systemd user-service is `active (running)`.
|
|
811
811
|
2. The LAN URL `http://<hostname>.local:<port>` opens the admin UI and the chat surface is interactive.
|
|
812
812
|
3. Cloudflare setup driven by the `cloudflare` plugin's `cloudflare` skill ends with `curl -I https://<hostname>.<your-zone>` returning `HTTP/2 200` from outside the LAN.
|
|
813
813
|
4. Reboot — both URLs are reachable again after boot without any manual action.
|
|
@@ -820,7 +820,7 @@ If any step fails, attach `$HOME/.<brand>/logs/install-<timestamp>.log` to the r
|
|
|
820
820
|
# Hetzner Cloud Install
|
|
821
821
|
Source: https://docs.getmaxy.com/install/hetzner.md
|
|
822
822
|
|
|
823
|
-
# Installing
|
|
823
|
+
# Installing SiteOffice Code on a Hetzner Cloud server
|
|
824
824
|
|
|
825
825
|
End-to-end install for a fresh Hetzner Cloud server on the **CAX31** tier (8 vCPU Ampere Altra ARM64, 16 GB RAM, 160 GB NVMe, ~€13/mo). CAX is the right tier because it is ARM64, identical chip family to the Raspberry Pi 5, so every binary built by the installer compiles the same way it does on the Pi. Every command is copy-pasteable and uses auto-yes flags so nothing prompts interactively.
|
|
826
826
|
|
|
@@ -1025,7 +1025,7 @@ Each installation has its own Cloudflare account. The **tunnel** sign-in is OAut
|
|
|
1025
1025
|
|
|
1026
1026
|
| Concept | Source |
|
|
1027
1027
|
|------|--------|
|
|
1028
|
-
| **Product identity** (
|
|
1028
|
+
| **Product identity** (SiteOffice vs Real Agent) | `brand.json` (`productName`, `configDir`) — known at install. |
|
|
1029
1029
|
| **Cloudflare account identity** | `cert.pem` from OAuth. One account per brand per device. |
|
|
1030
1030
|
| **Domain scope** (which zones the operator can route) | The operator picks the zone in the dashboard during OAuth or names it in chat; the agent can also enumerate zones via the API with a minted read-scoped token. |
|
|
1031
1031
|
| **Local tunnel state** | `~/{configDir}/cloudflared/` — `cert.pem`, `<UUID>.json`, `config.yml`, `alias-domains.json`. |
|
|
@@ -1141,15 +1141,15 @@ Each public agent has one of two access modes:
|
|
|
1141
1141
|
|
|
1142
1142
|
## How to Set It Up
|
|
1143
1143
|
|
|
1144
|
-
Tell
|
|
1144
|
+
Tell SiteOffice: "Set my public agent to gated access" or "Make the coaching agent invitation-only."
|
|
1145
1145
|
|
|
1146
|
-
|
|
1146
|
+
SiteOffice flips the agent's access mode. The next visitor to your public URL sees a sign-in screen instead of the chat.
|
|
1147
1147
|
|
|
1148
1148
|
## Inviting Visitors
|
|
1149
1149
|
|
|
1150
|
-
Tell
|
|
1150
|
+
Tell SiteOffice: "Invite sarah@client.co to the coaching agent."
|
|
1151
1151
|
|
|
1152
|
-
|
|
1152
|
+
SiteOffice creates an invitation and emails the visitor a magic link. At creation time the invitation is stamped with a one-off `sliceToken` — that token is what binds every per-visitor memory write to this specific invitation for the life of the invite.
|
|
1153
1153
|
|
|
1154
1154
|
Only email invitations are supported. Phone, OTP, and password flows are not part of the current build.
|
|
1155
1155
|
|
|
@@ -1170,7 +1170,7 @@ You can read what's in a visitor's slice via the cypher tools in conversation
|
|
|
1170
1170
|
|
|
1171
1171
|
## Managing Access
|
|
1172
1172
|
|
|
1173
|
-
All access management is done through conversation with
|
|
1173
|
+
All access management is done through conversation with SiteOffice:
|
|
1174
1174
|
|
|
1175
1175
|
- "Who has access to my coaching agent?" — lists active visitors and their `sliceToken`.
|
|
1176
1176
|
- "Revoke Sarah's access" — flips her grant to revoked AND immediately drops her active session, so she cannot continue talking on a live cookie. Her slice's historical memory stays in the graph; you can purge it separately if needed.
|
|
@@ -1185,19 +1185,19 @@ When a visitor is authenticated, your public agent knows their name and contact
|
|
|
1185
1185
|
|
|
1186
1186
|
## Action Approval
|
|
1187
1187
|
|
|
1188
|
-
External-facing actions — sending emails, WhatsApp messages, Telegram messages, and erasing contacts — require your approval before
|
|
1188
|
+
External-facing actions — sending emails, WhatsApp messages, Telegram messages, and erasing contacts — require your approval before SiteOffice executes them. This is human oversight as required by the EU AI Act.
|
|
1189
1189
|
|
|
1190
|
-
When
|
|
1190
|
+
When SiteOffice needs to send a message or perform a consequential action, it drafts the action and queues it for your review. You'll see it in your next chat turn:
|
|
1191
1191
|
|
|
1192
|
-
- "Approve it" —
|
|
1192
|
+
- "Approve it" — SiteOffice executes the action immediately
|
|
1193
1193
|
- "Reject it" — the action is cancelled
|
|
1194
|
-
- "Change the subject to X" —
|
|
1194
|
+
- "Change the subject to X" — SiteOffice modifies the action and executes the edited version
|
|
1195
1195
|
|
|
1196
1196
|
Internal operations (creating tasks, updating contacts, searching memory) execute automatically without approval.
|
|
1197
1197
|
|
|
1198
1198
|
### Changing the Policy
|
|
1199
1199
|
|
|
1200
|
-
Tell
|
|
1200
|
+
Tell SiteOffice to change which actions require approval:
|
|
1201
1201
|
|
|
1202
1202
|
- "Auto-send follow-up emails from now on" — emails execute without approval
|
|
1203
1203
|
- "Require approval for all WhatsApp messages" — restores the default gating
|
|
@@ -1207,7 +1207,7 @@ Changes are per-account and take effect immediately.
|
|
|
1207
1207
|
|
|
1208
1208
|
## Filesystem Access (SMB Share)
|
|
1209
1209
|
|
|
1210
|
-
Brand isolation extends to the device filesystem. Every
|
|
1210
|
+
Brand isolation extends to the device filesystem. Every SiteOffice install provisions an SMB share scoped to that brand's install folder, credentialled by the brand's install owner and the SiteOffice PIN. A device that hosts more than one brand carries one share per brand; tearing one brand down never exposes another brand's files. See [Samba Share](./samba.md) for the credential model, per-OS mount syntax, and peer-brand lifecycle.
|
|
1211
1211
|
|
|
1212
1212
|
---
|
|
1213
1213
|
# Settings
|
|
@@ -1217,36 +1217,36 @@ Source: https://docs.getmaxy.com/settings.md
|
|
|
1217
1217
|
|
|
1218
1218
|
## Output Style
|
|
1219
1219
|
|
|
1220
|
-
Controls how
|
|
1220
|
+
Controls how SiteOffice communicates with you.
|
|
1221
1221
|
|
|
1222
1222
|
| Style | Behaviour |
|
|
1223
1223
|
|-------|-----------|
|
|
1224
1224
|
| `default` | Concise, direct responses — gets to the point |
|
|
1225
1225
|
| `explanatory` | More detailed responses with educational context — explains reasoning and trade-offs |
|
|
1226
1226
|
|
|
1227
|
-
**Changing output style:** Tell
|
|
1227
|
+
**Changing output style:** Tell SiteOffice "Switch to explanatory mode" or "Use default output style."
|
|
1228
1228
|
|
|
1229
1229
|
Changes take effect on the next session. The current session continues with the existing style.
|
|
1230
1230
|
|
|
1231
1231
|
## Effort Level
|
|
1232
1232
|
|
|
1233
|
-
Controls how much work
|
|
1233
|
+
Controls how much work SiteOffice puts into each task — specifically, how many steps it takes before stopping and checking with you.
|
|
1234
1234
|
|
|
1235
1235
|
| Level | Max turns | Use when |
|
|
1236
1236
|
|-------|-----------|----------|
|
|
1237
1237
|
| `low` | 5 | Quick questions, simple lookups |
|
|
1238
1238
|
| `medium` | 10 | Standard tasks — most daily use |
|
|
1239
1239
|
| `high` | 20 | Complex multi-step tasks |
|
|
1240
|
-
| `auto` | 20 | Let
|
|
1240
|
+
| `auto` | 20 | Let SiteOffice decide (same ceiling as high) |
|
|
1241
1241
|
| `max` | 40 | Long autonomous workflows |
|
|
1242
1242
|
|
|
1243
|
-
**Changing effort level:** Tell
|
|
1243
|
+
**Changing effort level:** Tell SiteOffice "Set effort to high" or "Use low effort mode."
|
|
1244
1244
|
|
|
1245
1245
|
Changes take effect on the next session.
|
|
1246
1246
|
|
|
1247
1247
|
## Thinking View
|
|
1248
1248
|
|
|
1249
|
-
Controls how
|
|
1249
|
+
Controls how SiteOffice's thinking process is displayed in the chat.
|
|
1250
1250
|
|
|
1251
1251
|
| Mode | Behaviour |
|
|
1252
1252
|
|------|-----------|
|
|
@@ -1254,25 +1254,25 @@ Controls how Maxy's thinking process is displayed in the chat.
|
|
|
1254
1254
|
| `expanded` | Everything shown expanded — thinking, tool use, and results |
|
|
1255
1255
|
| `collapsed` | Everything collapsed — compact view, expand on tap |
|
|
1256
1256
|
|
|
1257
|
-
**Changing thinking view:** Tell
|
|
1257
|
+
**Changing thinking view:** Tell SiteOffice "Show thinking by default", "Show everything expanded", or "Hide thinking."
|
|
1258
1258
|
|
|
1259
1259
|
Changes take effect on the next session.
|
|
1260
1260
|
|
|
1261
1261
|
## Viewing Current Settings
|
|
1262
1262
|
|
|
1263
|
-
Ask
|
|
1263
|
+
Ask SiteOffice: "What are my current settings?" or "What output style am I using?"
|
|
1264
1264
|
|
|
1265
1265
|
## Default Agent
|
|
1266
1266
|
|
|
1267
1267
|
Controls which public agent serves the root URL (`/`). Visitors who go to your public site without specifying an agent slug see this agent.
|
|
1268
1268
|
|
|
1269
|
-
**Changing the default agent:** Tell
|
|
1269
|
+
**Changing the default agent:** Tell SiteOffice "Make sales the default agent" or "Set the default to support."
|
|
1270
1270
|
|
|
1271
1271
|
The change takes effect on the next page load. The previous default agent remains accessible at its `/{slug}` URL.
|
|
1272
1272
|
|
|
1273
1273
|
## Account Preferences
|
|
1274
1274
|
|
|
1275
|
-
You can ask
|
|
1275
|
+
You can ask SiteOffice to show or change any of the following:
|
|
1276
1276
|
|
|
1277
1277
|
- Default agent (which public agent serves the root URL)
|
|
1278
1278
|
- Admin model (which Claude model powers the admin agent)
|
|
@@ -1282,19 +1282,19 @@ You can ask Maxy to show or change any of the following:
|
|
|
1282
1282
|
- Context mode
|
|
1283
1283
|
- Enabled plugins
|
|
1284
1284
|
|
|
1285
|
-
Tell
|
|
1285
|
+
Tell SiteOffice what you want to change and it handles the rest.
|
|
1286
1286
|
|
|
1287
1287
|
## PIN
|
|
1288
1288
|
|
|
1289
|
-
Your admin PIN is set during initial setup. To change it, ask
|
|
1289
|
+
Your admin PIN is set during initial setup. To change it, ask SiteOffice: "Change my admin PIN."
|
|
1290
1290
|
|
|
1291
|
-
|
|
1291
|
+
SiteOffice will ask for your current PIN to verify, then set the new one.
|
|
1292
1292
|
|
|
1293
1293
|
## Adding admins
|
|
1294
1294
|
|
|
1295
|
-
To add another admin to your account, tell
|
|
1295
|
+
To add another admin to your account, tell SiteOffice: "Add {name} as an admin with PIN {pin}." SiteOffice creates the device-level user entry (`users.json`), the account-level role entry (`account.json` admins[]), and the graph identity (Neo4j AdminUser node) — the three stores stay in lockstep. If any leg fails, SiteOffice returns an error naming exactly which store is dirty and what was already written; the admin record is partial and may need manual reconciliation. PINs are unique across all users on the device — a new admin needs a PIN no one else on the device is using.
|
|
1296
1296
|
|
|
1297
|
-
If you ask
|
|
1297
|
+
If you ask SiteOffice to add an admin with a specific PIN and it returns a tier-cap or PIN-collision error, repeat the request with the same PIN every time you retry — otherwise SiteOffice auto-generates a different 4-digit PIN, silently substituting what you asked for.
|
|
1298
1298
|
|
|
1299
1299
|
---
|
|
1300
1300
|
# Contacts
|
|
@@ -1304,17 +1304,17 @@ Source: https://docs.getmaxy.com/contacts-guide.md
|
|
|
1304
1304
|
|
|
1305
1305
|
## What a Contact Is
|
|
1306
1306
|
|
|
1307
|
-
A contact is a Person node in
|
|
1307
|
+
A contact is a Person node in SiteOffice's memory graph. Each person has a first name and at least one identifier — email address, phone number, or both. Optional fields include last name and job title. Contacts are linked to conversations, other people, and business context.
|
|
1308
1308
|
|
|
1309
1309
|
## Adding a Contact
|
|
1310
1310
|
|
|
1311
|
-
Tell
|
|
1311
|
+
Tell SiteOffice naturally:
|
|
1312
1312
|
|
|
1313
1313
|
- "Add John Smith to my contacts — he's a potential client I met at the conference"
|
|
1314
1314
|
- "Create a contact for sarah@acme.com, her name is Sarah Chen, she's the head of procurement at Acme"
|
|
1315
1315
|
- "Add Hazel to contacts, phone +27747309676, she's a virtual assistant"
|
|
1316
1316
|
|
|
1317
|
-
|
|
1317
|
+
SiteOffice will extract the details and confirm the record before saving.
|
|
1318
1318
|
|
|
1319
1319
|
Required: first name and at least one of email or phone number. Everything else is optional but useful.
|
|
1320
1320
|
|
|
@@ -1327,11 +1327,11 @@ Ask naturally:
|
|
|
1327
1327
|
- "Find the contact from Acme procurement"
|
|
1328
1328
|
- "Look up +27747309676"
|
|
1329
1329
|
|
|
1330
|
-
|
|
1330
|
+
SiteOffice searches by name, email, phone number, or any detail you provide.
|
|
1331
1331
|
|
|
1332
1332
|
## Updating a Contact
|
|
1333
1333
|
|
|
1334
|
-
Tell
|
|
1334
|
+
Tell SiteOffice what changed:
|
|
1335
1335
|
|
|
1336
1336
|
- "Update John Smith's email to john@newcompany.com"
|
|
1337
1337
|
- "Add a note to Sarah Chen's record: prefers evening calls"
|
|
@@ -1351,27 +1351,27 @@ To remove a single contact from the graph:
|
|
|
1351
1351
|
- "Remove the duplicate contact for Sarah Chen"
|
|
1352
1352
|
- "Delete the contact with email dan@example.com"
|
|
1353
1353
|
|
|
1354
|
-
|
|
1354
|
+
SiteOffice will confirm which Person record matches, then remove the Person node and its direct relationships (e.g. links to conversations, other people) using a graph detach-delete. The contact is gone after confirmation — this cannot be undone.
|
|
1355
1355
|
|
|
1356
1356
|
This is different from GDPR erasure (`contact-erase`). Deleting a contact removes the Person node from the graph only. GDPR erasure cascades across all data stores — access credentials, conversations, messages, and emails — to satisfy an Article 17 right-to-erasure request. Use "delete" for routine contact cleanup; use "erase all data" when fulfilling a data subject's erasure request.
|
|
1357
1357
|
|
|
1358
1358
|
## Exporting Contact Data (GDPR Subject Access)
|
|
1359
1359
|
|
|
1360
|
-
When a person requests a copy of all data held about them, ask
|
|
1360
|
+
When a person requests a copy of all data held about them, ask SiteOffice:
|
|
1361
1361
|
|
|
1362
1362
|
- "Export all data we hold on john@example.com"
|
|
1363
1363
|
- "Show me everything we know about +447700900123"
|
|
1364
1364
|
|
|
1365
|
-
|
|
1365
|
+
SiteOffice gathers the Person record, access credentials, conversation history, and emails into a single structured document. The output is self-contained — it can be handed directly to the data subject to satisfy an Article 15 request.
|
|
1366
1366
|
|
|
1367
1367
|
## Erasing Contact Data (GDPR Right to Erasure)
|
|
1368
1368
|
|
|
1369
|
-
When a person requests deletion of all their data, ask
|
|
1369
|
+
When a person requests deletion of all their data, ask SiteOffice:
|
|
1370
1370
|
|
|
1371
1371
|
- "Delete all data we hold on john@example.com"
|
|
1372
1372
|
- "Erase everything for Sarah Chen"
|
|
1373
1373
|
|
|
1374
|
-
|
|
1374
|
+
SiteOffice first shows a preview of what would be deleted (counts per data type). Confirm the deletion to proceed. The erasure cascade covers:
|
|
1375
1375
|
|
|
1376
1376
|
- The Person record itself
|
|
1377
1377
|
- All access credentials (AccessGrant nodes)
|
|
@@ -1407,24 +1407,24 @@ The graph is the brain, and every turn that needs to know something runs the sam
|
|
|
1407
1407
|
|
|
1408
1408
|
## How Memory Works
|
|
1409
1409
|
|
|
1410
|
-
|
|
1410
|
+
SiteOffice maintains a graph of everything you've told it. Contacts, conversations, preferences, relationships, business context — all stored as connected nodes in a local Neo4j database on your Raspberry Pi.
|
|
1411
1411
|
|
|
1412
|
-
When you ask
|
|
1412
|
+
When you ask SiteOffice about something, it searches this graph first. It retrieves relevant context before responding, which is why SiteOffice can pick up where you left off even across separate sessions.
|
|
1413
1413
|
|
|
1414
1414
|
The graph lives entirely on your hardware. Nothing is sent to the cloud.
|
|
1415
1415
|
|
|
1416
1416
|
## What Gets Remembered
|
|
1417
1417
|
|
|
1418
|
-
|
|
1418
|
+
SiteOffice stores:
|
|
1419
1419
|
|
|
1420
1420
|
- **Contacts** — people, companies, relationships between them
|
|
1421
1421
|
- **Conversations** — key decisions, commitments, follow-ups mentioned in chat
|
|
1422
|
-
- **Preferences** — things you've told
|
|
1422
|
+
- **Preferences** — things you've told SiteOffice about how you like to work
|
|
1423
1423
|
- **Context** — project status, ongoing threads, background you've shared
|
|
1424
1424
|
|
|
1425
|
-
|
|
1425
|
+
SiteOffice remembers details you mention naturally: "I'm meeting with Sarah on Thursday" creates a memory that Thursday has a meeting with Sarah.
|
|
1426
1426
|
|
|
1427
|
-
## Telling
|
|
1427
|
+
## Telling SiteOffice to Remember Something
|
|
1428
1428
|
|
|
1429
1429
|
Just say it naturally:
|
|
1430
1430
|
|
|
@@ -1432,13 +1432,13 @@ Just say it naturally:
|
|
|
1432
1432
|
- "Note that the Johnson account is on hold until March"
|
|
1433
1433
|
- "My wife's name is Emma, keep that in mind"
|
|
1434
1434
|
|
|
1435
|
-
|
|
1435
|
+
SiteOffice will confirm and store it.
|
|
1436
1436
|
|
|
1437
|
-
## How
|
|
1437
|
+
## How SiteOffice learns how you work
|
|
1438
1438
|
|
|
1439
|
-
|
|
1439
|
+
SiteOffice also learns how you work without you having to teach it deliberately. Six broad areas cover the way most operators run a business — communication, scheduling, decisions, workflow, content, and interaction. Inside each area sits a small set of concrete fields (SiteOffice tracks around 28 in total) such as your preferred channel, quiet hours, workday start time, risk tolerance, content tonality, or address form. SiteOffice tracks which of these specific fields you have spoken into and which are still empty. While any are empty, it folds one organic question per turn into the conversation aimed at the next gap — never a list, never a form, never the same question twice. If you tell SiteOffice a field doesn't apply to you ("I work weekends, weekend availability isn't a thing for me"), it marks that field as covered and never re-asks. Once every field is either set or marked not-applicable, the proactive questions stop and SiteOffice answers what you ask without volunteering more. This is why session 300 should feel sharper than session 3: the longer you work together, the less SiteOffice needs to ask.
|
|
1440
1440
|
|
|
1441
|
-
## Telling
|
|
1441
|
+
## Telling SiteOffice to Forget Something
|
|
1442
1442
|
|
|
1443
1443
|
Be direct:
|
|
1444
1444
|
|
|
@@ -1447,7 +1447,7 @@ Be direct:
|
|
|
1447
1447
|
- "Clear what you know about my pricing preferences"
|
|
1448
1448
|
- "Delete that pricing guide I uploaded"
|
|
1449
1449
|
|
|
1450
|
-
|
|
1450
|
+
SiteOffice will confirm before deleting anything significant. Documents are soft-deleted first (excluded from search but recoverable for 7 days). Say "permanently delete" to remove immediately.
|
|
1451
1451
|
|
|
1452
1452
|
## Managing Documents
|
|
1453
1453
|
|
|
@@ -1455,27 +1455,27 @@ Maxy will confirm before deleting anything significant. Documents are soft-delet
|
|
|
1455
1455
|
|
|
1456
1456
|
Ask: "What files do I have stored?" or "List my attachments"
|
|
1457
1457
|
|
|
1458
|
-
|
|
1458
|
+
SiteOffice shows all uploaded files with their ingestion status — whether they've been processed into the knowledge graph.
|
|
1459
1459
|
|
|
1460
|
-
When you upload something for ingestion,
|
|
1460
|
+
When you upload something for ingestion, SiteOffice emits a one-line size estimate before it starts: short documents (<5K chars) classify in ~10s; mid-size (10K–20K chars) take ~45–90s; very large (>20K) up to ~3 minutes. If the classifier exceeds its 3-minute ceiling SiteOffice aborts loudly with a "Classifier unavailable — timeout" blocker and writes nothing — you can re-upload or split the document.
|
|
1461
1461
|
|
|
1462
1462
|
### Reading files
|
|
1463
1463
|
|
|
1464
1464
|
Ask: "Show me what's in the pricing guide" or "Read the quarterly report"
|
|
1465
1465
|
|
|
1466
|
-
|
|
1466
|
+
SiteOffice returns the full content of text and markdown files, extracted text from PDFs, and metadata for images.
|
|
1467
1467
|
|
|
1468
1468
|
### Editing files
|
|
1469
1469
|
|
|
1470
1470
|
Ask: "Update the pricing in that document" or "Change the introduction paragraph"
|
|
1471
1471
|
|
|
1472
|
-
|
|
1472
|
+
SiteOffice reads the file, makes the edit, and prepares it for re-ingestion into the knowledge graph. Only text and markdown files can be edited — PDFs and images cannot.
|
|
1473
1473
|
|
|
1474
1474
|
### Renaming files
|
|
1475
1475
|
|
|
1476
1476
|
Ask: "Rename that file to quarterly-report-q1.pdf"
|
|
1477
1477
|
|
|
1478
|
-
|
|
1478
|
+
SiteOffice updates the filename in both the stored metadata and the knowledge graph.
|
|
1479
1479
|
|
|
1480
1480
|
### Deleting documents
|
|
1481
1481
|
|
|
@@ -1495,15 +1495,15 @@ Ask naturally:
|
|
|
1495
1495
|
|
|
1496
1496
|
Three slash commands that apply analysis to what's already in your graph:
|
|
1497
1497
|
|
|
1498
|
-
**`/challenge <claim>`** — stress-tests an assertion.
|
|
1498
|
+
**`/challenge <claim>`** — stress-tests an assertion. SiteOffice searches your graph for nodes that contradict or qualify the claim — nodes that assert the opposite, name exceptions, or add significant caveats — and presents the strongest counter-case it finds. If nothing in your graph challenges the claim, it says so rather than inventing one. Results cite node IDs and relevance scores so you can inspect the sources directly.
|
|
1499
1499
|
|
|
1500
|
-
**`/connect <topic-A> <topic-B>`** — finds the bridge.
|
|
1500
|
+
**`/connect <topic-A> <topic-B>`** — finds the bridge. SiteOffice searches both topics, collects their immediate graph neighborhoods, and looks for nodes they share. If a direct bridge exists it names it in one sentence. If not, it surfaces the closest approach — the two nodes that are semantically nearest across the two sides — and proposes the connection you could draw.
|
|
1501
1501
|
|
|
1502
|
-
**`/emerge`** — names the unnamed clusters.
|
|
1502
|
+
**`/emerge`** — names the unnamed clusters. SiteOffice retrieves your KnowledgeDocument and Section nodes that are not yet connected to a Concept node, groups them by shared theme, and proposes a Concept name for each cluster. You approve or skip each proposal one at a time; nothing is written without your confirmation. Clusters of fewer than three nodes are listed at the end as "too small to cluster."
|
|
1503
1503
|
|
|
1504
1504
|
## Listing and counting
|
|
1505
1505
|
|
|
1506
|
-
|
|
1506
|
+
SiteOffice answers relational questions — "list all my people", "how many tasks do I have", "find the person with email X", "show me the 20 most recently created nodes" — via direct read-only Cypher against your Neo4j. This is faster and more precise than semantic search when the question is "the exact set where", not "things similar to".
|
|
1507
1507
|
|
|
1508
1508
|
You can also open a visual view of your graph at any time from the burger menu → **Graph**. Click the **Filter** button in the toolbar to open the filter menu — it lists only the top-level entity types in your schema (Conversation, Person, Task, KnowledgeDocument, …), one row per type, showing your per-type node count and sorted so the most-connected types sit at the top. Child types (messages inside a conversation, sections inside a document), conversation channel variants (admin vs public), message role variants (user vs assistant), and workflow execution plumbing (`ToolCall`, `WorkflowRun`, `WorkflowStep`, `StepResult`) never appear as filter rows — you reach children by clicking the parent and exploring its neighbourhood. Active rows render a force-directed map, coloured by label. Click a node to pivot into its 1-hop neighbourhood; click another node inside that neighbourhood to pivot again. Clicking a Message shows its details in the side panel; the Conversation view stays put — you read sibling messages without losing the chain on canvas. A breadcrumb strip above the canvas shows where you are (`Filter › Conversation › AssistantMessage`). The **Back** control pops one level — three clicks in always undoes with three Back presses; the filter view is the irreducible root. Click the **×** inside the filter menu to clear your chip selection. Type in the search box to highlight matches; submitting a search also widens the filter to include any node types the hits belong to, so relevant matches render instead of disappearing into a "not in current view" banner.
|
|
1509
1509
|
|
|
@@ -1511,17 +1511,17 @@ Conversations and Messages carry role/channel sublabels so you can read the chat
|
|
|
1511
1511
|
|
|
1512
1512
|
**Save a default view:** once you have the rows you want, click **Set default view** in the filter menu. Next time you open **Graph**, those rows are pre-selected and your data renders immediately. The default is per-admin, per-account — each admin on each account has their own.
|
|
1513
1513
|
|
|
1514
|
-
**Delete a node:** drag it to the trash icon top-right of the canvas. No confirmation — deletes are reversible for 30 days. To restore, toggle **Show trashed** inside the filter menu and click **Restore** on the node, or ask
|
|
1514
|
+
**Delete a node:** drag it to the trash icon top-right of the canvas. No confirmation — deletes are reversible for 30 days. To restore, toggle **Show trashed** inside the filter menu and click **Restore** on the node, or ask SiteOffice in chat ("restore the <label> I just deleted"). Deleting a conversation also trashes its messages in the same step, so they reappear together on restore.
|
|
1515
1515
|
|
|
1516
|
-
**Bulk cleanup of conversations in chat:** when you ask
|
|
1516
|
+
**Bulk cleanup of conversations in chat:** when you ask SiteOffice to clean up conversations in bulk ("trash all empty conversations," "clean up the single-assistant tests"), the agent uses a deterministic selector with a fixed set of filter names — it cannot author custom delete queries. The server re-runs the same filter on every candidate before it trashes, so a stale list can't destroy something the filter wouldn't match now. If the filter matches nothing, SiteOffice reports "no candidates" and nothing happens.
|
|
1517
1517
|
|
|
1518
|
-
The page reads only your own brand's Neo4j — a
|
|
1518
|
+
The page reads only your own brand's Neo4j — a SiteOffice device and a Real Agent device share no graph state even when on the same laptop. No credentials are required; the view inherits your admin session.
|
|
1519
1519
|
|
|
1520
|
-
**Typo-proof cypher.** When
|
|
1520
|
+
**Typo-proof cypher.** When SiteOffice runs direct Cypher to answer a relational question, the query is checked against your Neo4j's live label and relationship-type taxonomy before it executes. Cypher that references an unknown name (an edge or label that does not exist in your graph) is rejected for writes and flagged with a warnings header for reads, so SiteOffice never silently acts on a query that targeted the wrong set of nodes. You should not see this — it runs invisibly — but it is the safety net that stops a fabricated edge name from producing "empty" results that are really just unreachable. Before acting on a bulk operation SiteOffice surfaces the result count and a sample; if it ever describes a cypher rejection, that means its first attempt was malformed and it corrected itself.
|
|
1521
1521
|
|
|
1522
1522
|
## Bi-temporal timeline events
|
|
1523
1523
|
|
|
1524
|
-
Every factual statement
|
|
1524
|
+
Every factual statement SiteOffice extracts from your conversations is stored as a `:TimelineEvent` node. Each event carries two separate timestamps:
|
|
1525
1525
|
|
|
1526
1526
|
- **`occurredAt`** (valid-time) — when the fact was true in the world. Set from the text itself; can reference a date in the past ("Alice joined in 1990" stores `occurredAt = 1990-01-01`).
|
|
1527
1527
|
- **`learnedAt`** (transaction-time) — when the system ingested this event. Always the wall-clock time of the write; never back-dated.
|
|
@@ -1529,7 +1529,7 @@ Every factual statement Maxy extracts from your conversations is stored as a `:T
|
|
|
1529
1529
|
This distinction lets you ask two qualitatively different questions:
|
|
1530
1530
|
|
|
1531
1531
|
- *"What happened to Alice in 1990?"* — query by `occurredAt`.
|
|
1532
|
-
- *"What did
|
|
1532
|
+
- *"What did SiteOffice learn about Alice last Tuesday?"* — query by `learnedAt`.
|
|
1533
1533
|
|
|
1534
1534
|
`memory-compiled-truth-history` returns both fields for every timeline event on an entity under the `timelineEvents` array, alongside the compiled-truth revision history in the `revisions` array.
|
|
1535
1535
|
|
|
@@ -1537,31 +1537,31 @@ This distinction lets you ask two qualitatively different questions:
|
|
|
1537
1537
|
|
|
1538
1538
|
## Write doctrine
|
|
1539
1539
|
|
|
1540
|
-
Every new node in
|
|
1540
|
+
Every new node in SiteOffice's graph is created with at least one connection to an existing node. A contact connects to the conversation or organisation it came from; a task connects to the session that raised it or the entities it will affect; a session summary connects to the conversation it summarises. A node with no connection is noise — it cannot be attributed, traversed, or explained — so the graph refuses to create one. If SiteOffice ever tries to record something without a link, the write is rejected and SiteOffice asks you to clarify where it belongs.
|
|
1541
1541
|
|
|
1542
1542
|
Every node also carries a provenance stamp — which agent wrote it, in which session, via which tool. You never see these fields, but they are how operators trace unusual growth back to the code path that produced it, and why your graph stays clean over time.
|
|
1543
1543
|
|
|
1544
|
-
**Two write surfaces, one substrate.** General agents write through schema-aware helpers —
|
|
1544
|
+
**Two write surfaces, one substrate.** General agents write through schema-aware helpers — SiteOffice can record a new contact, a new commitment, a new preference without ever typing a database query, and the helper enforces the connection-and-provenance rule above structurally. The graph-steward role (the specialist SiteOffice dispatches when you ask for graph hygiene — "merge those two duplicate contacts," "wire those four tasks to the meeting," "rename the legacy label across the graph") additionally has a raw Cypher write tool for the multi-step operations the helpers cannot express. The steward role internalises the same connection-and-provenance discipline in its prompt; a post-write audit emits a warning on every breach so the same rules apply to both surfaces. Both paths feed the same hourly orphan trend and the same forensic provenance fields — read-side, you cannot tell the two apart, and that is the point.
|
|
1545
1545
|
|
|
1546
1546
|
## Vertical schemas
|
|
1547
1547
|
|
|
1548
|
-
On top of the base graph, each brand boots one optional **vertical** — an extra set of entity types tailored to a trade. The vertical is named by `brand.json#vertical` and defined in a `schema-<name>.md` reference; the memory plugin loads it at startup and validates every write against base + the active vertical. Real Agent boots `schema-estate-agent` (Listing, Property, Viewing, Offer). SiteOffice boots `schema-construction`, which adds the building-contractor entities — `Job`, `LineItem`, `Valuation`, `Milestone`, `QuoteDocument`, `VariationNote`, `InboundInvoice`, `SubContractor`, `TimeLog`, `SubInvoice`, `WhatsAppGroup` — grounded in real builder job folders so a job's quote, valuations, variations, supplier invoices, and subcontractor timesheets all hang off one `Job` node. The default
|
|
1548
|
+
On top of the base graph, each brand boots one optional **vertical** — an extra set of entity types tailored to a trade. The vertical is named by `brand.json#vertical` and defined in a `schema-<name>.md` reference; the memory plugin loads it at startup and validates every write against base + the active vertical. Real Agent boots `schema-estate-agent` (Listing, Property, Viewing, Offer). SiteOffice boots `schema-construction`, which adds the building-contractor entities — `Job`, `LineItem`, `Valuation`, `Milestone`, `QuoteDocument`, `VariationNote`, `InboundInvoice`, `SubContractor`, `TimeLog`, `SubInvoice`, `WhatsAppGroup` — grounded in real builder job folders so a job's quote, valuations, variations, supplier invoices, and subcontractor timesheets all hang off one `Job` node. The default SiteOffice brand boots no vertical (base graph only).
|
|
1549
1549
|
|
|
1550
1550
|
## Public-facing summaries for customer-readable subjects
|
|
1551
1551
|
|
|
1552
|
-
Some entities in your graph are knowable by people outside your team — companies you work with, projects you've delivered, the business itself. For those entities (
|
|
1552
|
+
Some entities in your graph are knowable by people outside your team — companies you work with, projects you've delivered, the business itself. For those entities (SiteOffice treats `:Organization`, `:Concept`, `:Project`, and `:LocalBusiness` this way), SiteOffice maintains two summaries: a private one only you and your specialist agents see, and a customer-facing public one your public agents are allowed to surface.
|
|
1553
1553
|
|
|
1554
|
-
Whenever
|
|
1554
|
+
Whenever SiteOffice updates the private summary on one of these entities, it automatically rewrites the public summary in the same step using a separate prompt that strips operator-voice ("needs follow-up", "action: chase next week"), internal sentiment, and anything that reads like a note-to-self. The two summaries stay in lockstep without you doing anything.
|
|
1555
1555
|
|
|
1556
|
-
If you want to write the public summary yourself — for instance, because the auto-generated version misses something you want customers to see — just tell
|
|
1556
|
+
If you want to write the public summary yourself — for instance, because the auto-generated version misses something you want customers to see — just tell SiteOffice the wording you want for the public summary on that entity, and SiteOffice will write it directly. It stays locked in for seven days; after that, the next automatic refresh can take over again, unless you re-pin it.
|
|
1557
1557
|
|
|
1558
1558
|
People entries (`:Person`) are deliberately excluded from this dual-summary system. Notes about contacts are private by definition and never get a public-facing form.
|
|
1559
1559
|
|
|
1560
1560
|
## Privacy
|
|
1561
1561
|
|
|
1562
|
-
All memory is stored on your local Raspberry Pi. The Neo4j database never leaves your network.
|
|
1562
|
+
All memory is stored on your local Raspberry Pi. The Neo4j database never leaves your network. SiteOffice does not sync memory to any cloud service or third party.
|
|
1563
1563
|
|
|
1564
|
-
If you want to wipe everything and start fresh, ask: "Reset my memory graph."
|
|
1564
|
+
If you want to wipe everything and start fresh, ask: "Reset my memory graph." SiteOffice will ask for confirmation before doing so.
|
|
1565
1565
|
|
|
1566
1566
|
---
|
|
1567
1567
|
# Projects
|
|
@@ -1577,13 +1577,13 @@ Projects are ideal when the user has work involving multiple people, sequential
|
|
|
1577
1577
|
|
|
1578
1578
|
## Creating a Project
|
|
1579
1579
|
|
|
1580
|
-
Tell
|
|
1580
|
+
Tell SiteOffice naturally:
|
|
1581
1581
|
|
|
1582
1582
|
- "Create a project for Mrs. Chen's kitchen refit — strip the old kitchen, plumbing first fix, electrical first fix, install units, then tiling and finishing"
|
|
1583
1583
|
- "Set up a project for the bathroom renovation, standard tier, due by end of June"
|
|
1584
1584
|
- "Start a project: boiler install for Sarah Thompson, quick job, just order parts, install, and test"
|
|
1585
1585
|
|
|
1586
|
-
|
|
1586
|
+
SiteOffice creates the project and all work items in one step. Dependencies between steps (e.g., "install units after plumbing and electrical") are set up automatically based on the order and relationships you describe.
|
|
1587
1587
|
|
|
1588
1588
|
Each project has a tier that reflects its complexity:
|
|
1589
1589
|
- **Quick** — straightforward, few steps (e.g., boiler install)
|
|
@@ -1599,32 +1599,32 @@ Ask naturally:
|
|
|
1599
1599
|
- "Show me the Davies bathroom project"
|
|
1600
1600
|
- "What should I focus on?"
|
|
1601
1601
|
|
|
1602
|
-
|
|
1602
|
+
SiteOffice shows project health at a glance:
|
|
1603
1603
|
- **Green** — on track, no issues
|
|
1604
1604
|
- **Amber** — warning signs (overdue task or blocker)
|
|
1605
1605
|
- **Red** — at risk (multiple overdue, critical blocker, or stale)
|
|
1606
1606
|
|
|
1607
|
-
When you start a new conversation,
|
|
1607
|
+
When you start a new conversation, SiteOffice automatically shows active project summaries so you know where things stand without asking.
|
|
1608
1608
|
|
|
1609
1609
|
## Updating a Project
|
|
1610
1610
|
|
|
1611
|
-
Tell
|
|
1611
|
+
Tell SiteOffice when things change:
|
|
1612
1612
|
|
|
1613
1613
|
- "Move the kitchen refit to the active phase"
|
|
1614
1614
|
- "The materials for the kitchen refit are delayed by a week"
|
|
1615
1615
|
- "Update the Davies bathroom target date to July 15th"
|
|
1616
1616
|
- "Change the boiler install to a standard tier — it's more complex than we thought"
|
|
1617
1617
|
|
|
1618
|
-
|
|
1618
|
+
SiteOffice records phase changes and issues as part of the project's history, creating an audit trail.
|
|
1619
1619
|
|
|
1620
1620
|
## Completing a Project
|
|
1621
1621
|
|
|
1622
|
-
Tell
|
|
1622
|
+
Tell SiteOffice:
|
|
1623
1623
|
|
|
1624
1624
|
- "Mark the boiler install as done"
|
|
1625
1625
|
- "Complete the kitchen refit project"
|
|
1626
1626
|
|
|
1627
|
-
If any work items are still pending,
|
|
1627
|
+
If any work items are still pending, SiteOffice will let you know and ask how to handle them — cancel, defer, or keep working on them.
|
|
1628
1628
|
|
|
1629
1629
|
## Abandoning a Project
|
|
1630
1630
|
|
|
@@ -1633,24 +1633,24 @@ If a project is no longer needed:
|
|
|
1633
1633
|
- "Abandon the Davies bathroom — client cancelled"
|
|
1634
1634
|
- "Stop the kitchen refit project"
|
|
1635
1635
|
|
|
1636
|
-
|
|
1636
|
+
SiteOffice records the reason and marks the project as abandoned.
|
|
1637
1637
|
|
|
1638
1638
|
## Projects vs. Tasks
|
|
1639
1639
|
|
|
1640
1640
|
Use a **task** for standalone work — a single action, a reminder, a follow-up. Use a **project** when the work has multiple steps that depend on each other, a client or stakeholder, and a lifecycle that progresses through phases.
|
|
1641
1641
|
|
|
1642
|
-
When you describe multi-step work,
|
|
1642
|
+
When you describe multi-step work, SiteOffice will ask if you'd like to structure it as a project. Over time, it learns your preference and stops asking.
|
|
1643
1643
|
|
|
1644
1644
|
## Working a Task End to End
|
|
1645
1645
|
|
|
1646
|
-
Ask
|
|
1646
|
+
Ask SiteOffice naturally:
|
|
1647
1647
|
|
|
1648
1648
|
- "What's outstanding?"
|
|
1649
1649
|
- "What's on my plate?"
|
|
1650
1650
|
- "What should I work on next?"
|
|
1651
1651
|
- "Pick something to do"
|
|
1652
1652
|
|
|
1653
|
-
|
|
1653
|
+
SiteOffice reads the ready set for your account, groups the open Tasks under their parent Projects, and asks you to pick one. You pick — it never auto-selects.
|
|
1654
1654
|
|
|
1655
1655
|
Once you pick, the loop runs end to end:
|
|
1656
1656
|
|
|
@@ -1660,7 +1660,7 @@ Once you pick, the loop runs end to end:
|
|
|
1660
1660
|
|
|
1661
1661
|
This means you can always trace a finished piece of work back to the Task that asked for it, and a Task that says "complete" always has its output attached.
|
|
1662
1662
|
|
|
1663
|
-
Cross-account access is refused. A Task that belongs to a different account on the same install is invisible to this loop —
|
|
1663
|
+
Cross-account access is refused. A Task that belongs to a different account on the same install is invisible to this loop — SiteOffice will not read it, name it, or surface it.
|
|
1664
1664
|
|
|
1665
1665
|
---
|
|
1666
1666
|
# Slides
|
|
@@ -1706,11 +1706,11 @@ Source: https://docs.getmaxy.com/telegram-guide.md
|
|
|
1706
1706
|
|
|
1707
1707
|
## What the Telegram Plugin Does
|
|
1708
1708
|
|
|
1709
|
-
The Telegram plugin connects
|
|
1709
|
+
The Telegram plugin connects SiteOffice to a Telegram bot. Once set up, you can:
|
|
1710
1710
|
|
|
1711
|
-
- Send messages to individuals or groups via
|
|
1712
|
-
- Receive messages from your Telegram bot and have
|
|
1713
|
-
- Use Telegram as a channel for
|
|
1711
|
+
- Send messages to individuals or groups via SiteOffice ("Send a message to the team: standup in 10 minutes")
|
|
1712
|
+
- Receive messages from your Telegram bot and have SiteOffice respond
|
|
1713
|
+
- Use Telegram as a channel for SiteOffice notifications and alerts
|
|
1714
1714
|
|
|
1715
1715
|
## Setup
|
|
1716
1716
|
|
|
@@ -1723,39 +1723,39 @@ The Telegram plugin connects Maxy to a Telegram bot. Once set up, you can:
|
|
|
1723
1723
|
|
|
1724
1724
|
### Step 2: Connect the plugin
|
|
1725
1725
|
|
|
1726
|
-
Tell
|
|
1726
|
+
Tell SiteOffice: "Set up Telegram" or "Configure the Telegram bot."
|
|
1727
1727
|
|
|
1728
|
-
|
|
1728
|
+
SiteOffice will ask for your bot token, then save it and activate the plugin. The bot is now connected.
|
|
1729
1729
|
|
|
1730
1730
|
### Step 3: Start the bot
|
|
1731
1731
|
|
|
1732
1732
|
In Telegram, open your bot and send `/start`. The bot is now active and listening.
|
|
1733
1733
|
|
|
1734
|
-
## Sending Messages via
|
|
1734
|
+
## Sending Messages via SiteOffice
|
|
1735
1735
|
|
|
1736
|
-
Once connected, tell
|
|
1736
|
+
Once connected, tell SiteOffice to send messages on your behalf:
|
|
1737
1737
|
|
|
1738
1738
|
- "Send a Telegram message to John: I'll be 10 minutes late"
|
|
1739
1739
|
- "Message the team channel: server maintenance at 11pm"
|
|
1740
1740
|
- "Tell Sarah via Telegram that the proposal is ready"
|
|
1741
1741
|
|
|
1742
|
-
|
|
1742
|
+
SiteOffice needs a chat ID or username to target a specific person or group. For groups, you'll need to add the bot to the group first.
|
|
1743
1743
|
|
|
1744
1744
|
## Getting a Chat ID
|
|
1745
1745
|
|
|
1746
|
-
To message a specific person or group,
|
|
1746
|
+
To message a specific person or group, SiteOffice needs their chat ID. The easiest way:
|
|
1747
1747
|
|
|
1748
1748
|
1. Have the person (or yourself) send any message to your bot
|
|
1749
|
-
2. Ask
|
|
1750
|
-
3.
|
|
1749
|
+
2. Ask SiteOffice: "What chat IDs have messaged the bot recently?"
|
|
1750
|
+
3. SiteOffice will look up the message history and show you the IDs
|
|
1751
1751
|
|
|
1752
1752
|
## Message History
|
|
1753
1753
|
|
|
1754
|
-
Ask
|
|
1754
|
+
Ask SiteOffice: "What messages has the bot received?" or "Show recent Telegram activity."
|
|
1755
1755
|
|
|
1756
1756
|
## Troubleshooting
|
|
1757
1757
|
|
|
1758
|
-
**Bot not responding:** Check that the bot token is correct — ask
|
|
1758
|
+
**Bot not responding:** Check that the bot token is correct — ask SiteOffice "What's my Telegram bot token configured as?" and verify it matches BotFather.
|
|
1759
1759
|
|
|
1760
1760
|
**Can't send to a group:** The bot must be a member of the group. Add it via the group settings in Telegram, then try again.
|
|
1761
1761
|
|
|
@@ -1771,7 +1771,7 @@ The `outlook` plugin gives the admin agent read-only access to Microsoft 365 / O
|
|
|
1771
1771
|
|
|
1772
1772
|
## Quickstart
|
|
1773
1773
|
|
|
1774
|
-
1. **Register an Entra app once per
|
|
1774
|
+
1. **Register an Entra app once per SiteOffice install** — see `platform/plugins/outlook/references/auth.md` for full steps. Set `OUTLOOK_CLIENT_ID` (and `OUTLOOK_TENANT_ID`, default `common`) in the operator's environment.
|
|
1775
1775
|
2. **Per account: register the Outlook account** — in admin chat, ask the agent to "register my Outlook account". The agent runs `outlook-account-register`, which prints an authorization URL.
|
|
1776
1776
|
3. **Open the URL in the VNC browser** — sign in to your Microsoft account, consent to the requested scopes (`offline_access`, `User.Read`, `Mail.Read`, `Calendars.Read`, `Contacts.Read`).
|
|
1777
1777
|
4. **Done.** Subsequent tool calls (mail, calendar, contacts) use the persisted refresh token transparently.
|
|
@@ -1841,7 +1841,7 @@ Source: https://docs.getmaxy.com/linkedin-extension.md
|
|
|
1841
1841
|
|
|
1842
1842
|
# LinkedIn Extension — operator guide
|
|
1843
1843
|
|
|
1844
|
-
Capture a LinkedIn profile or DM thread to your
|
|
1844
|
+
Capture a LinkedIn profile or DM thread to your SiteOffice graph with one click. The plugin ships a small Chrome extension; the admin already knows how to receive its payloads.
|
|
1845
1845
|
|
|
1846
1846
|
## Install (one time)
|
|
1847
1847
|
|
|
@@ -1849,7 +1849,7 @@ Capture a LinkedIn profile or DM thread to your Maxy graph with one click. The p
|
|
|
1849
1849
|
2. Toggle **Developer mode** on (top right).
|
|
1850
1850
|
3. Click **Load unpacked**.
|
|
1851
1851
|
4. Select `platform/plugins/linkedin-extension/extension/` on disk.
|
|
1852
|
-
5. Click the puzzle icon → pin **
|
|
1852
|
+
5. Click the puzzle icon → pin **SiteOffice LinkedIn Ingest** → open its options.
|
|
1853
1853
|
6. Paste two values:
|
|
1854
1854
|
- **Admin host** — your tunnel URL, e.g. `https://your-tunnel.example.com`.
|
|
1855
1855
|
- **Session key** — open your admin browser, copy the value of `session_key` from the cookie. (Same key the admin uses to authenticate every other admin request.)
|
|
@@ -1857,7 +1857,7 @@ Capture a LinkedIn profile or DM thread to your Maxy graph with one click. The p
|
|
|
1857
1857
|
|
|
1858
1858
|
## Use
|
|
1859
1859
|
|
|
1860
|
-
- **Profile** — open any `https://www.linkedin.com/in/<slug>/` page. An **Add to
|
|
1860
|
+
- **Profile** — open any `https://www.linkedin.com/in/<slug>/` page. An **Add to SiteOffice** pill appears in the top section. Click it. Within a few seconds the pill turns green: the profile is in your graph.
|
|
1861
1861
|
- **DM thread** — open any `https://www.linkedin.com/messaging/thread/<id>/` conversation. The same pill appears. Click it; the full transcript is captured plus the participants and any explicit commitments (meetings booked, actions promised, prices discussed).
|
|
1862
1862
|
- **Re-click** — the pill is idempotent. Re-clicking the same URL refreshes the document body and regenerates the summary; identities and entities `MERGE` rather than duplicate.
|
|
1863
1863
|
|
|
@@ -1877,7 +1877,7 @@ The plugin will never create `:Communication`, `:ConversationArchive` rows (i.e.
|
|
|
1877
1877
|
|
|
1878
1878
|
## When the pill turns amber
|
|
1879
1879
|
|
|
1880
|
-
The pill shows **Sign in to
|
|
1880
|
+
The pill shows **Sign in to SiteOffice** when your session key has expired. Click it to open the options page; paste a fresh `session_key` from your admin browser; save. The next click on the LinkedIn pill will succeed.
|
|
1881
1881
|
|
|
1882
1882
|
## When the pill turns red
|
|
1883
1883
|
|
|
@@ -2145,7 +2145,7 @@ Source: https://docs.getmaxy.com/voice-mirror-guide.md
|
|
|
2145
2145
|
|
|
2146
2146
|
## What It Does
|
|
2147
2147
|
|
|
2148
|
-
|
|
2148
|
+
SiteOffice reads emails, posts, documents, and your own chat messages, and uses them to make sure agent-drafted copy reads like you wrote it — not like generic AI prose.
|
|
2149
2149
|
|
|
2150
2150
|
Anthropic models cannot be fine-tuned. Voice mirror works by feeding the model two things alongside every drafting task:
|
|
2151
2151
|
|
|
@@ -2156,24 +2156,24 @@ The model conditions on both and produces copy that reads as yours.
|
|
|
2156
2156
|
|
|
2157
2157
|
Voice mirror maintains a separate profile for each type of content you write: plain text, email, social posts, articles, notes, and marketing copy. The right profile is applied automatically based on what you're drafting.
|
|
2158
2158
|
|
|
2159
|
-
When
|
|
2159
|
+
When SiteOffice produces anything that will go out under your name (a document, public-facing copy, anything you will send onward), it applies your voice before it writes the first line, not after you ask for a rewrite. You do not have to request it.
|
|
2160
2160
|
|
|
2161
2161
|
## How Your Voice Is Captured
|
|
2162
2162
|
|
|
2163
2163
|
### Automatically — from chat
|
|
2164
2164
|
|
|
2165
|
-
Every admin chat session feeds your writing into the `text` profile automatically. When the session ends,
|
|
2165
|
+
Every admin chat session feeds your writing into the `text` profile automatically. When the session ends, SiteOffice reads the transcript, filters out slash commands, system messages, and large paste blocks, and adds each genuine turn as a corpus entry. This happens in the background with no action needed from you.
|
|
2166
2166
|
|
|
2167
2167
|
### Via backfill — from historical content
|
|
2168
2168
|
|
|
2169
|
-
Use the backfill flow to teach
|
|
2169
|
+
Use the backfill flow to teach SiteOffice your writing from emails, documents, and social posts you've already written.
|
|
2170
2170
|
|
|
2171
2171
|
In the admin chat, ask: **"Start the voice-mirror backfill."**
|
|
2172
2172
|
|
|
2173
|
-
|
|
2173
|
+
SiteOffice asks which stream to backfill first — discrete documents (emails, posts, PDFs) or chat archives (WhatsApp, Telegram, etc.). **Pick chat archives first if you have any imported.** Chat is where your unguarded voice lives; email is the same voice in dress clothes.
|
|
2174
2174
|
|
|
2175
|
-
- **Chat archives** — tag a whole conversation in one click.
|
|
2176
|
-
- **Documents and posts** — paginated 10 at a time.
|
|
2175
|
+
- **Chat archives** — tag a whole conversation in one click. SiteOffice doesn't ask about individual messages because chunks within a conversation almost always share the same voice. Options per conversation: yours, mixed (multiple authors on your side — rare), or not yours (e.g. a Slack channel where you only forwarded other people's messages).
|
|
2176
|
+
- **Documents and posts** — paginated 10 at a time. SiteOffice shows each item with its detected format (email, article, note, social-post). Tag the whole batch, a subset by number, or per-item if you want a precise label like `human-led-agent-assisted` (you wrote the content, SiteOffice polished). Override the detected format if one is wrong.
|
|
2177
2177
|
|
|
2178
2178
|
Skip a batch if none qualify, or stop at any time — the next session resumes where you left off.
|
|
2179
2179
|
|
|
@@ -2181,13 +2181,13 @@ Skip a batch if none qualify, or stop at any time — the next session resumes w
|
|
|
2181
2181
|
|
|
2182
2182
|
Once you have corpus entries tagged (or after automatic PTY ingestion fills the `text` profile), ask: **"Build my voice profile."**
|
|
2183
2183
|
|
|
2184
|
-
|
|
2184
|
+
SiteOffice reads the corpus for each format, summarises your style as a YAML card, and saves it to the graph. It picks up your sentence rhythms, the constructions you reach for, the words you avoid — separately for email, articles, social posts, and so on.
|
|
2185
2185
|
|
|
2186
2186
|
The profile re-runs automatically when your corpus grows by ≥20% for any format or every 30 days, whichever comes first.
|
|
2187
2187
|
|
|
2188
2188
|
## Feedback Loop
|
|
2189
2189
|
|
|
2190
|
-
When you edit an agent draft before sending — shorten a sentence, change a sign-off, swap a phrase —
|
|
2190
|
+
When you edit an agent draft before sending — shorten a sentence, change a sign-off, swap a phrase — SiteOffice captures the edit and feeds it into the next distillation. The more you edit, the closer the voice gets.
|
|
2191
2191
|
|
|
2192
2192
|
This happens silently as part of the edit-loop in any drafting skill (email composition is the first wired surface).
|
|
2193
2193
|
|
|
@@ -2200,7 +2200,7 @@ Voice mirror is on by default for every drafting skill. To opt out for one, set
|
|
|
2200
2200
|
- **Blend voices** — one profile set per person, no "Joel + Neo combined".
|
|
2201
2201
|
- **Copy public figures** — voice mirror only learns from your own writing.
|
|
2202
2202
|
- **Clone audio** — text only, no speech synthesis.
|
|
2203
|
-
- **Guess** — historical content stays `unknown` until you mark it.
|
|
2203
|
+
- **Guess** — historical content stays `unknown` until you mark it. SiteOffice never auto-classifies your writing. (Automatic ingestion applies only to your live PTY sessions where authorship is certain.)
|
|
2204
2204
|
|
|
2205
2205
|
## Status
|
|
2206
2206
|
|
|
@@ -2223,7 +2223,7 @@ SDK-resume contract). This file is the index that points at them.
|
|
|
2223
2223
|
|
|
2224
2224
|
The `maxy-code/` tree does **not** ship a `.docs/platform.md` developer
|
|
2225
2225
|
doc. The legacy root tree (`getmaxy/`) carries one at
|
|
2226
|
-
`.docs/platform.md` for the original
|
|
2226
|
+
`.docs/platform.md` for the original SiteOffice installer; the SiteOffice Code tree
|
|
2227
2227
|
keeps its architecture surface in two places:
|
|
2228
2228
|
|
|
2229
2229
|
- `maxy-code-prd.md` at the repo root — product requirements and the
|
|
@@ -2444,7 +2444,7 @@ chat stays live.
|
|
|
2444
2444
|
SOUL / KNOWLEDGE) auto-save on type via
|
|
2445
2445
|
`POST /api/admin/sidebar-artefact-save`.
|
|
2446
2446
|
- Read-only artefacts (specialist agent templates) cannot be edited
|
|
2447
|
-
because they ship with
|
|
2447
|
+
because they ship with SiteOffice and would be overwritten on the next
|
|
2448
2448
|
install.
|
|
2449
2449
|
- PDF artefacts render inline; non-PDF binaries fall back to a Download
|
|
2450
2450
|
button when the browser has no native viewer.
|
|
@@ -2658,7 +2658,7 @@ Source: https://docs.getmaxy.com/neo4j.md
|
|
|
2658
2658
|
|
|
2659
2659
|
# Neo4j edge types — operator reference
|
|
2660
2660
|
|
|
2661
|
-
How
|
|
2661
|
+
How SiteOffice's graph wires itself.
|
|
2662
2662
|
|
|
2663
2663
|
## Typed-edge auto-extraction
|
|
2664
2664
|
|
|
@@ -2726,9 +2726,9 @@ Source: https://docs.getmaxy.com/internals.md
|
|
|
2726
2726
|
|
|
2727
2727
|
# Platform Internals — Retrieval Architecture
|
|
2728
2728
|
|
|
2729
|
-
Technical architecture reference for the retrieval pipeline, knowledge delivery, and supporting infrastructure. This document covers how information moves from the Neo4j graph into an agent's context — the mechanics behind "
|
|
2729
|
+
Technical architecture reference for the retrieval pipeline, knowledge delivery, and supporting infrastructure. This document covers how information moves from the Neo4j graph into an agent's context — the mechanics behind "SiteOffice searches this graph to retrieve relevant context."
|
|
2730
2730
|
|
|
2731
|
-
Use this reference when assessing capabilities, diagnosing retrieval behaviour, or answering questions about how the platform works internally. When a question asks "does
|
|
2731
|
+
Use this reference when assessing capabilities, diagnosing retrieval behaviour, or answering questions about how the platform works internally. When a question asks "does SiteOffice have X?" — check here before asserting a gap.
|
|
2732
2732
|
|
|
2733
2733
|
---
|
|
2734
2734
|
|
|
@@ -3051,13 +3051,13 @@ This tool is read-only and available to both public and admin agents.
|
|
|
3051
3051
|
|
|
3052
3052
|
### When conversations are created
|
|
3053
3053
|
|
|
3054
|
-
`:Conversation` nodes on webchat (admin login, "New conversation" in the burger, a new public visitor) are created lazily. Opening the chat or logging in does not write anything to the graph —
|
|
3054
|
+
`:Conversation` nodes on webchat (admin login, "New conversation" in the burger, a new public visitor) are created lazily. Opening the chat or logging in does not write anything to the graph — SiteOffice only records the conversation once the user sends a second message. This keeps `conversation-search` and the Conversations modal free of one-turn abandoned threads. WhatsApp and Telegram take the opposite posture: every inbound — DM or group, allowed or activation-off, agent-invoked or gated — MERGEs the `:Conversation` and writes a forensic `:Message:WhatsAppMessage` row before any access-control decision. The graph is the durable record of every message the device received, not just the ones the agent replied to. See `.docs/web-chat.md` "Deferred conversation persistence" and `.docs/whatsapp.md` "Session continuity" for the full contract.
|
|
3055
3055
|
|
|
3056
3056
|
Each row in the Conversations modal exposes a `View logs` row-action that opens a popover with three links — **Stream**, **Errors**, **SSE** — each of which targets `/api/admin/logs?type={stream|error|sse}&sessionId={full-id}` in a new tab. The row's 8-char id chip is click-to-copy; hover reveals the full `sessionId` as a tooltip. See `.docs/web-chat.md` "In-chat retrieval" for the route contract and `console.debug` observability.
|
|
3057
3057
|
|
|
3058
3058
|
### Static publish surface — `/sites/*`
|
|
3059
3059
|
|
|
3060
|
-
|
|
3060
|
+
SiteOffice hosts a generic per-account static-tree publish surface at `https://public.<brand>/sites/<...>/<file>`. The route serves files from `<accountDir>/sites/<...>` with URL=disk mirroring — operator drops the tree on disk, no upload API. Extended MIME covers HTML/CSS/JS/woff2/fonts on top of images. Path traversal (`..`, encoded `..`, segments failing `SAFE_SEG_RE`) returns 403; symlinks escaping the sites root are rejected via a `realpathSync` re-check. `.html` responses carry `Content-Security-Policy: default-src 'self' https: data:; script-src 'none'` and `Cache-Control: no-cache`; assets are cached for an hour; every response carries `X-Content-Type-Options: nosniff`. Per-account isolation comes from `resolveAccount` — every brand's install sees only its own tree.
|
|
3061
3061
|
|
|
3062
3062
|
**Directory canonicalisation.** A request whose disk target is a directory is `301`'d to the trailing-slash form (query string preserved) before any body is served — RFC 3986 §5.3 base resolution requires the trailing slash so relative refs in the served HTML resolve under the directory, not its parent. After the redirect the route serves `<dir>/index.html` if it exists on disk; otherwise `404`. There is **no** implicit-`index.html` invention for missing paths — the publisher owns canonical URLs. A brochure shipped without `index.html` is reached at `/sites/<slug>/<file>.html`, and the admin skill `publish-site` is the sanctioned surface that moves the extracted tree under `<accountDir>/sites/<slug>/` and emits the canonical path slug. Operator-side: drop a brochure at `<accountDir>/sites/properties/<id>/brochure/output/` and it serves at `<public-host>/sites/properties/<id>/brochure/output/brochure.html` (or `<public-host>/sites/properties/<id>/brochure/output/` if that directory contains an `index.html`). See `.docs/web-chat.md` `/sites/*` route entry for the wire contract and `[sites]` log lines (`serve|redirect-trailing-slash|not-found|path-traversal-rejected|symlink-escape-rejected|no-account`).
|
|
3063
3063
|
|
|
@@ -3065,7 +3065,7 @@ Maxy hosts a generic per-account static-tree publish surface at `https://public.
|
|
|
3065
3065
|
|
|
3066
3066
|
### Cross-tab session rotation
|
|
3067
3067
|
|
|
3068
|
-
When you click "New conversation" in the chat tab,
|
|
3068
|
+
When you click "New conversation" in the chat tab, SiteOffice mints a fresh admin session key on the server and clears the old one. Sibling admin tabs (`/graph`, `/data`) opened in the same browser keep working without re-login: the chat tab broadcasts the new key on a same-origin channel so each sibling tab updates its captured key instantly, and any in-flight admin request that 401s with the rotation-orphan code retries once after re-reading the latest key from per-tab storage. If neither path recovers (browser locked down, second 401 after retry, session expired), the tab shows a single banner — "Your admin session was renewed in another tab. Click to reload." — and one click sends you back through login. No silent 401s; no re-clicking through the same trash icon hoping it sticks. See `.docs/web-chat.md` "Cross-tab rotation contract" for the wire-level `code` taxonomy and observability surfaces.
|
|
3069
3069
|
|
|
3070
3070
|
---
|
|
3071
3071
|
|
|
@@ -3227,7 +3227,7 @@ Each ToolCall record contains:
|
|
|
3227
3227
|
| startedAt / completedAt | Timestamps for the invocation |
|
|
3228
3228
|
| sessionId | Links back to the originating conversation |
|
|
3229
3229
|
|
|
3230
|
-
Records persist indefinitely and are queryable by the admin agent. Ask
|
|
3230
|
+
Records persist indefinitely and are queryable by the admin agent. Ask SiteOffice "what tools ran in the last session?" or "show me all tool calls from today" to review the audit trail.
|
|
3231
3231
|
|
|
3232
3232
|
Workflow-dispatched tool calls are tracked separately via `StepResult` nodes (part of the workflow execution system) and are not duplicated as ToolCall nodes.
|
|
3233
3233
|
|
|
@@ -3258,7 +3258,7 @@ See `.docs/neo4j.md § Process provenance doctrine` for the full enforcement con
|
|
|
3258
3258
|
|
|
3259
3259
|
## Context compaction
|
|
3260
3260
|
|
|
3261
|
-
When an admin turn crosses 75% of the model's context window,
|
|
3261
|
+
When an admin turn crosses 75% of the model's context window, SiteOffice runs a silent compaction turn that asks the agent to call the `session-compact` MCP tool with a structured briefing (what you asked for, what was done, decisions made, work-in-progress, things you've shared about yourself). The briefing is written to Neo4j; the next admin turn injects it back into the system prompt, so continuity survives across the compaction boundary without re-sending the full transcript.
|
|
3262
3262
|
|
|
3263
3263
|
The compaction runs against a transient one-shot pool entry separate from the long-lived admin Query. Operator-visible side effects:
|
|
3264
3264
|
- Compaction logs land in `claude-agent-compaction-stream-YYYY-MM-DD.log` alongside the main stream log. Look for `[compaction-start]`, `[compaction-summary-captured]`, `[compaction-failed]`, `[compaction-timeout]`, `[compaction-crashed]`, or `[compaction-spawn-error]` to triage. Subprocess stderr is captured inline as `[subproc-stderr] <line>` — there is no longer a separate `claude-agent-compaction-stderr-…log` file.
|
|
@@ -3290,7 +3290,7 @@ npx -y @rubytech/create-realagent-code # realagent brand
|
|
|
3290
3290
|
|
|
3291
3291
|
**Hostname / printed URL.** Without `--hostname`, the installer reads `scutil --get LocalHostName` and prints the completion URL as `http://<that-name>.local:<port>`. No sudo, no system change — your Mac's existing local network name is what mDNS will resolve. With `--hostname <h>`, the installer sets `HostName` / `LocalHostName` / `ComputerName` to `<h>` via `sudo scutil` (one password prompt, all-or-nothing rollback within the three-call batch) so the URL becomes `http://<h>.local:<port>`. Grep `~/.<brand>/logs/install-*.log` for `[create-maxy] darwin-hostname-mode=` to confirm which path ran (`scutil-get`, `scutil-set`, or `brand-fallback`).
|
|
3292
3292
|
|
|
3293
|
-
**LaunchAgent.** The installer registers `
|
|
3293
|
+
**LaunchAgent.** The installer registers `SiteOffice` as a launchd LaunchAgent at `~/Library/LaunchAgents/com.rubytech.<brand-hostname>.plist` — for example `com.rubytech.maxy-code.plist`. Survives logout/login and reboot via `KeepAlive=true` and `RunAtLoad=true`. Two brands on the same Mac get two distinct plists (brand-hostname-keyed), so install order is independent. Use `launchctl print gui/$UID/com.rubytech.<brand-hostname>` for service state. The `[create-maxy] launchd-plist=<path> loaded=true` line in the install log confirms `launchctl bootstrap` accepted the plist; `loaded=false exit=<n>` is the failure signal (run `plutil -lint <path>` to diagnose).
|
|
3294
3294
|
|
|
3295
3295
|
**Cloudflare on darwin.** The installer brew-installs the `cloudflared` binary so it is on PATH, but does not invoke `cloudflared service install` or `cloudflared tunnel route dns` — public reach is opt-in. After install, the operator runs `cloudflared tunnel login` (browser-driven) followed by the existing tunnel-setup flow if they want a public address. Grep `[create-maxy] darwin-cloudflare-skip=true` in the install log to confirm the installer took the documented skip path.
|
|
3296
3296
|
|
|
@@ -3309,7 +3309,7 @@ Every successful Mac install contains, in order: `platform=darwin`, `darwin-host
|
|
|
3309
3309
|
|
|
3310
3310
|
## Initial Setup
|
|
3311
3311
|
|
|
3312
|
-
The
|
|
3312
|
+
The SiteOffice installer handles the full setup. Run it on your Pi:
|
|
3313
3313
|
|
|
3314
3314
|
```bash
|
|
3315
3315
|
npx -y @rubytech/create-maxy
|
|
@@ -3324,7 +3324,7 @@ This installs all dependencies (Node.js, Neo4j, Cloudflare tunnel, Claude Code),
|
|
|
3324
3324
|
3. Installs and starts Neo4j (the memory database)
|
|
3325
3325
|
4. Installs and configures the Cloudflare tunnel for remote access
|
|
3326
3326
|
5. Creates your account and sets your PIN
|
|
3327
|
-
6. Starts the
|
|
3327
|
+
6. Starts the SiteOffice web server on port 19200
|
|
3328
3328
|
7. Configures systemd so everything restarts automatically if the Pi reboots
|
|
3329
3329
|
|
|
3330
3330
|
## First admin session — install-time defaults
|
|
@@ -3378,7 +3378,7 @@ Diagnostic line per spawn (`~/.<brand>/logs/server.log`):
|
|
|
3378
3378
|
|
|
3379
3379
|
The `pty-spawn-start` line additionally carries `hooksResolved=<event1,event2,…>` — the hook event names Claude Code would actually load for that PTY (resolved by walking the same `$CLAUDE_CONFIG_DIR/settings.json` plus the cwd-to-.git path Claude Code itself uses). A Stop hook registered in a settings file outside the loader's scope shows up as a missing event in this list.
|
|
3380
3380
|
|
|
3381
|
-
Zero `aboutOwnerBytes` on any admin spawn is a regression: the upstream resolver dropped the field entirely. The prose body always carries the unconditional MAXIMISE imperative on line two, so the byte count is positive even on a fresh-account spawn whose line one is `NOTHING`. Zero `dormantPluginsBytes` on a
|
|
3381
|
+
Zero `aboutOwnerBytes` on any admin spawn is a regression: the upstream resolver dropped the field entirely. The prose body always carries the unconditional MAXIMISE imperative on line two, so the byte count is positive even on a fresh-account spawn whose line one is `NOTHING`. Zero `dormantPluginsBytes` on a SiteOffice install with `cloudflare` not enabled is likewise a regression. Zero `pluginManifestBytes` on any account with enabled plugins means the upstream walker failed silently.
|
|
3382
3382
|
|
|
3383
3383
|
The manager also runs a boot-time self-test that renders a fixture compose call against synthetic inputs and refuses to start if any sentinel is missing:
|
|
3384
3384
|
|
|
@@ -3398,9 +3398,9 @@ Companion lint: `platform/scripts/check-no-esm-require.mjs` rejects `require(` c
|
|
|
3398
3398
|
|
|
3399
3399
|
## Service Management
|
|
3400
3400
|
|
|
3401
|
-
|
|
3401
|
+
SiteOffice runs via systemd and starts automatically on boot. You don't need to start it manually. To check if it's running, ask SiteOffice "Check system status."
|
|
3402
3402
|
|
|
3403
|
-
If you need to restart the service manually (rare), ask
|
|
3403
|
+
If you need to restart the service manually (rare), ask SiteOffice to do it for you.
|
|
3404
3404
|
|
|
3405
3405
|
## Browsing the brand filesystem on your LAN (SMB)
|
|
3406
3406
|
|
|
@@ -3408,23 +3408,23 @@ Every install provisions a per-brand SMB share against the brand's install folde
|
|
|
3408
3408
|
|
|
3409
3409
|
## Remote Access via Cloudflare
|
|
3410
3410
|
|
|
3411
|
-
|
|
3411
|
+
SiteOffice uses a Cloudflare tunnel to make your local Pi accessible from anywhere without opening router ports. The tunnel is configured during setup and runs as a background service.
|
|
3412
3412
|
|
|
3413
|
-
Setting it up: say "Set up remote access."
|
|
3413
|
+
Setting it up: say "Set up remote access." SiteOffice walks you through signing into Cloudflare, picking your domain (if you have more than one on your Cloudflare account), and then shows a form where you pick a short name that becomes your admin address. For example, entering `joel` gives you `https://joel.your-domain.com` for admin access. You can also pick a separate address for the public chat, or leave it blank to skip public access. The form only accepts valid address characters (lowercase letters, numbers, hyphens) — SiteOffice never asks you to type your full URL in chat.
|
|
3414
3414
|
|
|
3415
3415
|
Your admin URL looks like: `https://joel.maxy.chat` (the short name is whatever you picked in the form).
|
|
3416
3416
|
|
|
3417
|
-
To check the tunnel status: ask
|
|
3417
|
+
To check the tunnel status: ask SiteOffice "Check Cloudflare tunnel status."
|
|
3418
3418
|
|
|
3419
|
-
To restart the tunnel: ask
|
|
3419
|
+
To restart the tunnel: ask SiteOffice "Restart the Cloudflare tunnel."
|
|
3420
3420
|
|
|
3421
3421
|
## Checking Service Status
|
|
3422
3422
|
|
|
3423
|
-
Ask
|
|
3423
|
+
Ask SiteOffice: "Check system status."
|
|
3424
3424
|
|
|
3425
3425
|
The `system-status` tool reports the health of all services: Neo4j, the web server, the Cloudflare tunnel, and all active MCP servers.
|
|
3426
3426
|
|
|
3427
|
-
## If
|
|
3427
|
+
## If SiteOffice Won't Start
|
|
3428
3428
|
|
|
3429
3429
|
From the Pi directly:
|
|
3430
3430
|
|
|
@@ -3466,9 +3466,9 @@ A separate operator-side harness at `platform/scripts/installer-device-verify.sh
|
|
|
3466
3466
|
|
|
3467
3467
|
## Plugin registration at install time
|
|
3468
3468
|
|
|
3469
|
-
The installer registers Claude Code plugins on the device as the last step before the brand service starts. After registration, `claude plugin list` on the Pi shows every
|
|
3469
|
+
The installer registers Claude Code plugins on the device as the last step before the brand service starts. After registration, `claude plugin list` on the Pi shows every SiteOffice platform plugin shipped by the brand, every premium sub-plugin shipped by the brand, and any external plugins the brand declares (e.g. Telegram, Discord, iMessage from `claude-plugins-official`). Spawned `claude` sessions inherit those plugins from `~/.claude/` — the session manager passes no `--mcp-config` argv.
|
|
3470
3470
|
|
|
3471
|
-
**Where the manifests come from.** The
|
|
3471
|
+
**Where the manifests come from.** The SiteOffice plugin source tree uses `PLUGIN.md` (YAML frontmatter) for plugin metadata, not Claude Code's native `.claude-plugin/plugin.json`. At bundle time, `scripts/generate-plugin-manifests.mjs` walks the payload and synthesises a Claude-Code-native `plugin.json` per plugin plus a `marketplace.json` at each tree root. The generator runs in `packages/create-maxy-code/scripts/bundle.js` after platform + premium plugins are copied into the payload, so the deployed install directory carries:
|
|
3472
3472
|
|
|
3473
3473
|
- `<INSTALL_DIR>/platform/plugins/<name>/.claude-plugin/plugin.json` per platform plugin
|
|
3474
3474
|
- `<INSTALL_DIR>/platform/plugins/.claude-plugin/marketplace.json` (marketplace `maxy-platform`)
|
|
@@ -3517,17 +3517,17 @@ External channel plugins (telegram, discord) are installed but not configured at
|
|
|
3517
3517
|
|
|
3518
3518
|
## Running multiple brands on one device
|
|
3519
3519
|
|
|
3520
|
-
A single Pi or laptop can host more than one brand (for example
|
|
3520
|
+
A single Pi or laptop can host more than one brand (for example SiteOffice and Real Agent) side by side. Each brand runs as its own service on its own port, with its own install directory and its own data. Installing one brand does not touch the other.
|
|
3521
3521
|
|
|
3522
|
-
- **Separate:** each brand has its own install folder (`~/maxy/`, `~/realagent/`), its own config folder (`~/.maxy/`, `~/.realagent/`), its own web port, its own Cloudflare tunnel state, its own edge systemd unit (`maxy-edge.service` vs `realagent-edge.service`), and by default its own Neo4j database (
|
|
3522
|
+
- **Separate:** each brand has its own install folder (`~/maxy/`, `~/realagent/`), its own config folder (`~/.maxy/`, `~/.realagent/`), its own web port, its own Cloudflare tunnel state, its own edge systemd unit (`maxy-edge.service` vs `realagent-edge.service`), and by default its own Neo4j database (SiteOffice on bolt port 7687, Real Agent on 7688). Action runner units are transient and per-invocation, not per-brand, so no naming conflict is possible.
|
|
3523
3523
|
- **Brand-isolated Neo4j:** when a brand provisions a dedicated Neo4j instance (any port other than 7687), the installer stops and disables the apt-package's system `neo4j.service` after enabling the brand-dedicated unit, so only one Neo4j process holds the shared `/var/lib/neo4j/run/` PID file. The seed step receives the brand-correct `NEO4J_URI` and `NEO4J_PASSWORD` as explicit environment variables — the seed script no longer carries a `bolt://localhost:7687` default. A failed dedicated start aborts the install loudly with a journalctl tail; there is no silent fallback to the system instance. Stop/disable targets the literal `neo4j.service` only, so peer brands running their own `neo4j-{brand}.service` are unaffected.
|
|
3524
|
-
- **Peer-aware system-unit guard:** before stopping the system `neo4j.service`, the installer checks whether any other brand on the device still depends on it — that is, has `NEO4J_URI=bolt://localhost:7687` in its `~/.<peer>/.env`. If so, the system unit is left enabled and active, and the install log shows `[neo4j] system unit kept active — peer brand <name> depends on port 7687` instead of the usual `[neo4j] disabling system unit` line. This prevents a `create-realagent` install from disabling
|
|
3524
|
+
- **Peer-aware system-unit guard:** before stopping the system `neo4j.service`, the installer checks whether any other brand on the device still depends on it — that is, has `NEO4J_URI=bolt://localhost:7687` in its `~/.<peer>/.env`. If so, the system unit is left enabled and active, and the install log shows `[neo4j] system unit kept active — peer brand <name> depends on port 7687` instead of the usual `[neo4j] disabling system unit` line. This prevents a `create-realagent` install from disabling SiteOffice's database on a host where SiteOffice still uses the shared system instance (the earlier platform fixes reproducer on Neo's laptop, 2026-04-28). On single-brand hosts and on multi-brand hosts where every peer runs a dedicated port, behaviour is unchanged. The dedicated unit exports `NEO4J_HOME=<per-brand-data-dir>` alongside `NEO4J_CONF`, so `server.directories.run`, `server.directories.plugins`, and `server.directories.import` resolve per-brand — no collision with `/var/lib/neo4j/run/neo4j.pid`. The conf sed-overrides, mkdir-p, chown, and unit-write are idempotent and re-run on every install, so a host whose prior install left a broken unit recovers on retry.
|
|
3525
3525
|
- **Shared:** both brands share the system Chromium/VNC stack, the Ollama model server, and the `cloudflared` command itself. Browser automation is serialised — one admin session at a time across both brands.
|
|
3526
3526
|
|
|
3527
3527
|
To install a second brand on a device that already runs the first, just run the other installer. No flags needed for isolation:
|
|
3528
3528
|
|
|
3529
3529
|
```bash
|
|
3530
|
-
# Already running
|
|
3530
|
+
# Already running SiteOffice on port 20000. Install Real Agent on a different port:
|
|
3531
3531
|
npx -y @rubytech/create-realagent --port 19500
|
|
3532
3532
|
```
|
|
3533
3533
|
|
|
@@ -3560,13 +3560,13 @@ Empty output from step 3 = brand.json resolved cleanly and the badge reflects th
|
|
|
3560
3560
|
|
|
3561
3561
|
## Upgrading
|
|
3562
3562
|
|
|
3563
|
-
To upgrade
|
|
3563
|
+
To upgrade SiteOffice to the latest version, ask SiteOffice: "Upgrade SiteOffice." The platform checks the current device identity (hostname and port via `system-status`), then re-runs the installer with explicit `--hostname` and `--port` flags to preserve them across the upgrade.
|
|
3564
3564
|
|
|
3565
3565
|
The docs plugin (this plugin) is upgraded in the same step — you always have the documentation that matches your installed version.
|
|
3566
3566
|
|
|
3567
3567
|
### Automatic upgrade alert
|
|
3568
3568
|
|
|
3569
|
-
|
|
3569
|
+
SiteOffice checks for new releases on every admin session start — whenever you log in, reload the page, or return to the admin chat. When a newer version is available, the Software Update window opens automatically showing your current and the latest version, with a one-click Upgrade button. Dismissing the window (click outside or the close button) defers the alert until your next login or reload; no alert is shown when you are already on the latest version.
|
|
3570
3570
|
|
|
3571
3571
|
The upgrade runs inside a live terminal embedded in the Software Update window — you see each installation step stream as it happens, and any password prompts from `sudo` appear directly in the terminal for you to answer. Closing the window does not cancel the upgrade; re-opening it reattaches to the same shell so you can see what happened while disconnected.
|
|
3572
3572
|
|
|
@@ -3578,7 +3578,7 @@ Source: https://docs.getmaxy.com/samba.md
|
|
|
3578
3578
|
|
|
3579
3579
|
# Samba Share
|
|
3580
3580
|
|
|
3581
|
-
Every
|
|
3581
|
+
Every SiteOffice install provisions a per-brand SMB network share so you can read and write the brand's install folder from Finder, File Explorer, the Files app on iOS, or any SMB-capable client on Android or Linux. No client install required — every modern OS speaks SMB natively.
|
|
3582
3582
|
|
|
3583
3583
|
The share lives next to the rest of the brand. On a device that runs more than one brand, each brand gets its own stanza, its own credentials, and its own lifecycle. Tearing one brand down never touches another brand's share.
|
|
3584
3584
|
|
|
@@ -3610,7 +3610,7 @@ If `<hostname>.local` does not resolve from your client (some networks do not ro
|
|
|
3610
3610
|
## Credentials
|
|
3611
3611
|
|
|
3612
3612
|
- **Username** — the Unix user that owns the install on the device. On a Pi or Hetzner box this is `admin`; on a self-hosted Linux laptop it is whatever Linux user ran the installer (for example `neo`). The installer persists this value to `~/.<brand>/.install-owner` so every later read uses the same identity the installer wrote.
|
|
3613
|
-
- **Password** — your current
|
|
3613
|
+
- **Password** — your current SiteOffice PIN. The same PIN that unlocks the admin UI unlocks the SMB share.
|
|
3614
3614
|
|
|
3615
3615
|
Both halves are required. SMB never accepts a guest connection; `map to guest = bad user` is set in the global stanza.
|
|
3616
3616
|
|
|
@@ -3760,8 +3760,8 @@ tail -200 ~/.maxy/logs/maxy-ui.log | rg '\[remote-auth\].*resolvedKind='
|
|
|
3760
3760
|
**Symptom:** You send a message and nothing comes back, or the response never arrives.
|
|
3761
3761
|
|
|
3762
3762
|
**Check:**
|
|
3763
|
-
1. Ask
|
|
3764
|
-
2. Check the platform logs: ask
|
|
3763
|
+
1. Ask SiteOffice: "Check system status" — the `system-status` tool will report whether all services are running
|
|
3764
|
+
2. Check the platform logs: ask SiteOffice "Show me the recent logs"
|
|
3765
3765
|
3. If the admin agent itself won't start: restart the platform (see below)
|
|
3766
3766
|
|
|
3767
3767
|
**Common causes:**
|
|
@@ -3769,17 +3769,17 @@ tail -200 ~/.maxy/logs/maxy-ui.log | rg '\[remote-auth\].*resolvedKind='
|
|
|
3769
3769
|
- Platform process has stopped — restart it
|
|
3770
3770
|
- Network issue if accessing remotely — check your Cloudflare tunnel is running
|
|
3771
3771
|
|
|
3772
|
-
**If the chat shows a single `[agent-loop-stop] same error twice — aborting` line and stops:**
|
|
3772
|
+
**If the chat shows a single `[agent-loop-stop] same error twice — aborting` line and stops:** SiteOffice hit the same structured tool failure twice in a row inside one turn (e.g. a permission gate refused the same write twice, or two `Read` calls hit the same missing file). The runtime aborted the turn after the second occurrence to save tokens instead of running until the SDK turn budget exhausted. The blocker text names the tool and the first line of the error. Resolve the underlying cause (re-run the named skill, fix the missing prerequisite, etc.) and tap "Continue" — the next turn truly resumes the prior SDK session via the synthetic-tool-result contract, so SiteOffice picks up where it aborted instead of cold-querying its own session list. To see the diagnostic, ask SiteOffice: "Show me the most recent stall-recovery log line." Greppable post-deploy invariants: `[agent-loop-stop] reason=identical-tool-failure tool=<name> errorSignature=<sha8> toolInputDigest=<sha8>` followed by `[stall-recovery] kind=agent_loop_stop … handoff=resume-first` and on the next turn `[stall-resume] consumed kind=agent_loop_stop toolUseId=<8> priorSessionId=<8>`. The fallback path (when the SDK session id was lost) emits `handoff=metadata-only` + `[recovery-handoff] generated/consumed reason=agent-loop-stop` and the chat button reads "Start over" instead of "Continue". A `[recovery-handoff] WARN missing-on-cold-create` line means the fallback briefing wasn't persisted — surface to support.
|
|
3773
3773
|
|
|
3774
|
-
**If a background task goes silent and the chat shows "A background task went silent — K of M completed":**
|
|
3774
|
+
**If a background task goes silent and the chat shows "A background task went silent — K of M completed":** SiteOffice's subagent stopped emitting progress for over 2 minutes. Tap "Continue" — the next turn resumes the prior session and reads a synthetic tool_result describing what completed before the pause, so the agent re-plans without losing the work it had done. Most stalls are upstream API latency rather than the subagent's approach failing — the resume-first path treats both correctly. Greppable post-deploy invariants: `[stall-recovery] kind=subagent_stalled … completed=<K>/? handoff=resume-first` followed by `[stall-resume] consumed kind=subagent_stalled toolUseId=<8>` on the next turn. If the button reads "Start over" instead, the parent's pending tool_use_id was not captured — the fallback path took over; the prior conversation is preserved as a `<recovery-context>` block in the cold-started session.
|
|
3775
3775
|
|
|
3776
3776
|
**Agent searches the filesystem after uploading a zip.** If you uploaded a zip and the agent burns several turns running `find` / `Glob` instead of unzipping, that is the symptom of the recovery-retry attachment-context regression (now closed by the recovery context preservation contract in `.docs/agents.md`). Greppable confirmation is the `[context-overflow-recovery] retry … attachmentsCarried=<n>` line in the conversation stream log. If you see `[context-overflow-recovery] WARN attachment-context-lost`, the regression has returned — surface to support.
|
|
3777
3777
|
|
|
3778
|
-
**Turn budget exhausted with a horizontal rule separating two assistant turns.** When
|
|
3778
|
+
**Turn budget exhausted with a horizontal rule separating two assistant turns.** When SiteOffice reaches its turn budget and the doubled retry also runs out, the chat now shows a one-paragraph assistant message that opens with `error_max_turns turns=A→B` (initial budget → final budget) followed by the recovery copy: "I reached my turn budget of N before I could finish this request. Try sending a smaller or more focused request, or ask me to use higher effort." That message is persisted to the graph, so the next page-refresh still shows it. The thin horizontal rule labelled "Session restored after timeout." that appears above your following turn signals that the prior turn forced a cold SDK-session restart inside the same conversation (pool eviction) — the agent's response after the rule is from a fresh SDK session even though the conversation thread is unchanged. Greppable post-deploy invariants: `[context-overflow-recovery] exhausted cause=max-turns-interrupted` count equals `[admin-persist] writer=persistMessageExhaust outcome=ok` count for the same sessionId window, and one `[session-store] storeAgentSessionId` line marks the cold-restart that drove the on-screen rule.
|
|
3779
3779
|
|
|
3780
3780
|
|
|
3781
3781
|
**A turn rendered in chat is missing on next page-refresh.** Pre-the 2026-05-07 mandate this was a class of silent failure — Neo4j persists were wrapped in a no-op error catch and a write that threw left the artefact "rendered then disappeared on resume". The 2026-05-07 mandate makes JSONL canonical: the resume route reads the SDK transcript file at `~/.claude/projects/<project-key>/<sessionId>.jsonl` first, supplements from Neo4j, and triggers async heal-on-resume writes for any turn the JSONL has but Neo4j does not. So a refreshed conversation always renders what the SDK saw, regardless of write outcome. If a heal write itself fails, the chat shows a top-of-conversation banner naming the count; if every heal succeeds the resume is silent and the missing rows are quietly restored to Neo4j. Greppable post-deploy invariants in the per-session stream log (`logs/claude-agent-stream-<sessionKey>.log`): `[admin-resume] reason=<…> source=<jsonl|jsonl-missing|neo4j-only>` (one per resume), `[admin-persist] convId=<8> writer=<…> outcome=<ok|fail|skip>` (per persist site), `[admin-persist-heal] convId=<8> turnIndex=<n> outcome=<ok|fail>` (per heal write). To force-audit a specific conversation against its Neo4j projection without re-executing it, run `tsx platform/scripts/admin-persist-audit.ts --conversation-id=<uuid> --account-id=<uuid> --session-id=<uuid>` — non-zero exit + per-divergence `[admin-persist-audit] expected=<message|component> missing reason=neo4j-row-absent` lines name what would have been silently lost pre-mandate.
|
|
3782
|
-
**Wrong Claude account answering on a multi-brand device.** On a host running both
|
|
3782
|
+
**Wrong Claude account answering on a multi-brand device.** On a host running both SiteOffice and Real Agent, each brand's admin agent reads its own `~/${brand.configDir}/.claude/.credentials.json`; there is no longer a shared `~/.claude/` thrashing them against one another. If a brand reports auth failures or appears to be operating against the wrong subscription, check three things:
|
|
3783
3783
|
1. `grep "\[claude-auth\] init" ~/.${brand}/logs/server.log | tail -1` — the resolved path must end with `~/.${brand}/.claude/.credentials.json`. If a `[claude-auth] WARN cross-brand-path-detected` line is present, the runtime is still pointing at `~/.claude/`; the brand main service did not pick up the `Environment=CLAUDE_CONFIG_DIR=` setting (re-run the brand installer to refresh the unit file).
|
|
3784
3784
|
2. `diff <(jq .claudeAiOauth.accessToken ~/.maxy/.claude/.credentials.json) <(jq .claudeAiOauth.accessToken ~/.realagent/.claude/.credentials.json)` — must be non-empty after each brand's operator has run `claude /login` against distinct Anthropic accounts; if it's empty, both brands are still logged in to the same account (operator action, not a code bug).
|
|
3785
3785
|
3. `grep "\[install\] claude-creds pickup" ~/.${brand}/logs/install-*.log` — fires once on the first post-Task-923 install of any brand and moves the legacy `~/.claude/.credentials.json` into that brand's path. Subsequent brands install with no credentials and require a fresh `claude /login` inside that brand's chat (which writes to the brand-scoped path because the systemd unit env is in scope).
|
|
@@ -3795,15 +3795,15 @@ tail -200 ~/.maxy/logs/maxy-ui.log | rg '\[remote-auth\].*resolvedKind='
|
|
|
3795
3795
|
|
|
3796
3796
|
## Memory Not Working
|
|
3797
3797
|
|
|
3798
|
-
**Symptom:**
|
|
3798
|
+
**Symptom:** SiteOffice doesn't remember things you've told it, or search returns nothing.
|
|
3799
3799
|
|
|
3800
3800
|
**Check:**
|
|
3801
|
-
1. Ask
|
|
3802
|
-
2. Ask
|
|
3801
|
+
1. Ask SiteOffice: "Check the Neo4j connection"
|
|
3802
|
+
2. Ask SiteOffice: "Search memory for [something you know was stored]"
|
|
3803
3803
|
|
|
3804
3804
|
**Common causes:**
|
|
3805
3805
|
- Neo4j service stopped — restart the platform, which restarts Neo4j
|
|
3806
|
-
- Memory index is stale — ask
|
|
3806
|
+
- Memory index is stale — ask SiteOffice: "Reindex memory"
|
|
3807
3807
|
|
|
3808
3808
|
---
|
|
3809
3809
|
|
|
@@ -3812,12 +3812,12 @@ tail -200 ~/.maxy/logs/maxy-ui.log | rg '\[remote-auth\].*resolvedKind='
|
|
|
3812
3812
|
**Symptom:** You send a message to the bot and nothing happens.
|
|
3813
3813
|
|
|
3814
3814
|
**Check:**
|
|
3815
|
-
1. Confirm the bot token is correct: ask
|
|
3815
|
+
1. Confirm the bot token is correct: ask SiteOffice "What Telegram bot token is configured?"
|
|
3816
3816
|
2. Verify the bot is running: send `/start` to the bot in Telegram
|
|
3817
|
-
3. Check the MCP server logs: ask
|
|
3817
|
+
3. Check the MCP server logs: ask SiteOffice "Show Telegram plugin logs"
|
|
3818
3818
|
|
|
3819
3819
|
**Common causes:**
|
|
3820
|
-
- Bot token changed (if you regenerated it in BotFather) — update it by telling
|
|
3820
|
+
- Bot token changed (if you regenerated it in BotFather) — update it by telling SiteOffice "Update my Telegram bot token"
|
|
3821
3821
|
- Webhook not connected — restart the platform
|
|
3822
3822
|
|
|
3823
3823
|
---
|
|
@@ -3827,11 +3827,11 @@ tail -200 ~/.maxy/logs/maxy-ui.log | rg '\[remote-auth\].*resolvedKind='
|
|
|
3827
3827
|
**Symptom:** A tool fails with an error, or a plugin says it can't connect.
|
|
3828
3828
|
|
|
3829
3829
|
**Check:**
|
|
3830
|
-
1. Ask
|
|
3831
|
-
2. Ask
|
|
3830
|
+
1. Ask SiteOffice: "Show me recent errors"
|
|
3831
|
+
2. Ask SiteOffice: "Restart the [plugin name] plugin"
|
|
3832
3832
|
|
|
3833
3833
|
**Common causes:**
|
|
3834
|
-
- Missing environment variable (API key, token) — the error message will name it; ask
|
|
3834
|
+
- Missing environment variable (API key, token) — the error message will name it; ask SiteOffice to help configure it
|
|
3835
3835
|
- MCP server crashed — restarting the platform restarts all MCP servers
|
|
3836
3836
|
|
|
3837
3837
|
---
|
|
@@ -3842,7 +3842,7 @@ tail -200 ~/.maxy/logs/maxy-ui.log | rg '\[remote-auth\].*resolvedKind='
|
|
|
3842
3842
|
|
|
3843
3843
|
**Check:**
|
|
3844
3844
|
1. Confirm you have set a PIN in the admin UI at least once. On a fresh Pi or Hetzner box the `smbpasswd` entry does not exist until the first set-pin runs — mounts before that point always fail.
|
|
3845
|
-
2. Use the install owner as the username (`admin` on a Pi or Hetzner box; the Linux user that ran the installer on a self-hosted laptop) and the current
|
|
3845
|
+
2. Use the install owner as the username (`admin` on a Pi or Hetzner box; the Linux user that ran the installer on a self-hosted laptop) and the current SiteOffice PIN as the password. The SMB password is not stored separately — it is the PIN.
|
|
3846
3846
|
3. If `<hostname>.local` does not resolve from your client, mount by LAN IP instead (`smb://192.168.1.50` on macOS, `\\192.168.1.50\<brand>` on Windows).
|
|
3847
3847
|
4. Rotate the PIN in the admin UI. That re-triggers the `smbpasswd` sync on the device. If the resync log line reads `[set-pin] smbpasswd sync failed owner=<unknown> rc=-1 reason=install-owner-file-missing`, restore `~/.<brand>/.install-owner` from the installer log.
|
|
3848
3848
|
|
|
@@ -3852,35 +3852,35 @@ See [Samba Share](./samba.md) for the full credential model and per-OS mount syn
|
|
|
3852
3852
|
|
|
3853
3853
|
## Restarting the Platform
|
|
3854
3854
|
|
|
3855
|
-
From the admin interface, ask
|
|
3855
|
+
From the admin interface, ask SiteOffice: "Restart the platform."
|
|
3856
3856
|
|
|
3857
|
-
If
|
|
3857
|
+
If SiteOffice itself isn't responding (the page loads but the agent won't connect), try refreshing the browser. If the page itself won't load, the platform process may have stopped — power-cycle the Raspberry Pi by unplugging and reconnecting power, then wait a minute for services to restart automatically.
|
|
3858
3858
|
|
|
3859
3859
|
---
|
|
3860
3860
|
|
|
3861
3861
|
## Checking Logs
|
|
3862
3862
|
|
|
3863
|
-
Ask
|
|
3863
|
+
Ask SiteOffice: "Show me the logs" or "Show errors from the last hour."
|
|
3864
3864
|
|
|
3865
3865
|
For specific plugin logs: "Show Telegram logs" or "Show contacts plugin logs."
|
|
3866
3866
|
|
|
3867
|
-
|
|
3867
|
+
SiteOffice has access to all platform logs and can filter them for you.
|
|
3868
3868
|
|
|
3869
3869
|
---
|
|
3870
3870
|
|
|
3871
3871
|
## Cloudflare Tunnel Down (Remote Access Broken)
|
|
3872
3872
|
|
|
3873
|
-
**Symptom:** You can reach
|
|
3873
|
+
**Symptom:** You can reach SiteOffice on your local network but not via your public domain.
|
|
3874
3874
|
|
|
3875
|
-
**Check:** Ask
|
|
3875
|
+
**Check:** Ask SiteOffice "Check the Cloudflare tunnel status."
|
|
3876
3876
|
|
|
3877
|
-
**Fix:** Ask
|
|
3877
|
+
**Fix:** Ask SiteOffice "Restart the Cloudflare tunnel."
|
|
3878
3878
|
|
|
3879
|
-
If the tunnel won't reconnect, re-run the Cloudflare setup: ask
|
|
3879
|
+
If the tunnel won't reconnect, re-run the Cloudflare setup: ask SiteOffice "Reconnect Cloudflare."
|
|
3880
3880
|
|
|
3881
|
-
If the initial Cloudflare login fails during setup,
|
|
3881
|
+
If the initial Cloudflare login fails during setup, SiteOffice will fall back to asking you for a connection key. You can create one in the Cloudflare dashboard (SiteOffice will guide you through this in the browser).
|
|
3882
3882
|
|
|
3883
|
-
**If you switched Cloudflare accounts or are stuck on the wrong one:** ask
|
|
3883
|
+
**If you switched Cloudflare accounts or are stuck on the wrong one:** ask SiteOffice "Reset my Cloudflare login and start over." This is a clean reset — SiteOffice clears every stored credential, then opens a fresh browser sign-in. The next sign-in binds to whichever Cloudflare account you choose, with no risk of the previous account's stored credentials silently coming back.
|
|
3884
3884
|
|
|
3885
3885
|
---
|
|
3886
3886
|
|
|
@@ -3888,9 +3888,9 @@ If the initial Cloudflare login fails during setup, Maxy will fall back to askin
|
|
|
3888
3888
|
|
|
3889
3889
|
`maxy-edge.service` (always-on front door) classifies upstream errors and serves a brand-aware response. There are two distinct user-visible shapes; the right one depends on what failed.
|
|
3890
3890
|
|
|
3891
|
-
**Branded holding page (brand logo + "Starting") for ~10 s during an upgrade — this is expected and self-healing.** The edge process binds the public port immediately, but `maxy.service` (the upstream UI) takes ~10 s after restart to apply the neo4j schema and mount its 11 routes. Any browser navigation that lands during that window gets a self-contained HTML holding page that polls `/api/health` and reloads automatically once the upstream binds. The page renders the brand logo (inlined as a base64 data URI at edge boot from `<install>/server/public/brand/<assets.logo>`) and the brand display/body fonts (loaded from fonts.googleapis.com) — both paths bypass the unavailable upstream so the page never makes a same-origin asset fetch. When `brand.logoContainsName` is true the logo replaces the productName text; otherwise the page falls back to "
|
|
3891
|
+
**Branded holding page (brand logo + "Starting") for ~10 s during an upgrade — this is expected and self-healing.** The edge process binds the public port immediately, but `maxy.service` (the upstream UI) takes ~10 s after restart to apply the neo4j schema and mount its 11 routes. Any browser navigation that lands during that window gets a self-contained HTML holding page that polls `/api/health` and reloads automatically once the upstream binds. The page renders the brand logo (inlined as a base64 data URI at edge boot from `<install>/server/public/brand/<assets.logo>`) and the brand display/body fonts (loaded from fonts.googleapis.com) — both paths bypass the unavailable upstream so the page never makes a same-origin asset fetch. When `brand.logoContainsName` is true the logo replaces the productName text; otherwise the page falls back to "SiteOffice is starting". No operator action required. The diagnostic line in `~/.maxy/logs/edge.log` is `[edge] upstream http error path=… err=connect ECONNREFUSED 127.0.0.1:<UPSTREAM_PORT> err-class=econnrefused-coldstart upstream=…` and disappears as soon as upstream binds. Boot-time confirmation that the logo resolved: `[edge] brand=<name> holding-logo=inlined assets-dir=<path>` — `holding-logo=missing` means the logo file wasn't found at `assets-dir`, the page degrades to text-only.
|
|
3892
3892
|
|
|
3893
|
-
**Branded plain-text 502 ("Bad Gateway (
|
|
3893
|
+
**Branded plain-text 502 ("Bad Gateway (SiteOffice unavailable)") — real upstream failure, not cold-start.** Any error class other than `ECONNREFUSED` (timeouts, resets, host-unreachable) returns the existing 502 path. The diagnostic line carries `err-class=other`. Read the log with `tail -200 ~/.maxy/logs/edge.log | rg 'err-class=other'` and check `~/.maxy/logs/server.log` for upstream stack traces — the upstream itself is the source.
|
|
3894
3894
|
|
|
3895
3895
|
**Continuous `err-class=econnrefused-coldstart` for >30 s past the last `[edge] listening` line** indicates the upstream never binds — the upgrade or boot has stalled. Recover via `sudo systemctl --user status maxy.service` and check the action runner log per the next section. Permanent-failure UI escalation (turning the holding page into an error after N seconds) is intentionally deferred.
|
|
3896
3896
|
|