@rubytech/create-maxy-code 0.1.172 → 0.1.175
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/dist/index.js +12 -1
- package/package.json +1 -1
- package/payload/platform/neo4j/schema.cypher +49 -10
- package/payload/platform/plugins/docs/references/voice-mirror-guide.md +18 -16
- package/payload/platform/scripts/setup-account.sh +8 -0
- package/payload/platform/scripts/verify-skill-tool-surface.sh +117 -0
- package/payload/platform/services/claude-session-manager/dist/specialist-drift.d.ts.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/specialist-drift.js +1 -0
- package/payload/platform/services/claude-session-manager/dist/specialist-drift.js.map +1 -1
- package/payload/platform/templates/specialists/agents/content-producer.md +4 -4
- package/payload/platform/templates/specialists/agents/librarian.md +2 -2
- package/payload/platform/templates/specialists/agents/personal-assistant.md +4 -4
- package/payload/platform/templates/specialists/agents/project-manager.md +2 -2
- package/payload/platform/templates/specialists/agents/research-assistant.md +2 -2
- package/payload/premium-plugins/writer-craft/PLUGIN.md +11 -7
- package/payload/premium-plugins/writer-craft/hooks/__tests__/voice-session-end-text.test.sh +284 -0
- package/payload/premium-plugins/writer-craft/hooks/voice-session-end-text.sh +75 -0
- package/payload/premium-plugins/writer-craft/mcp/dist/cli/ingest-session-text.d.ts +3 -0
- package/payload/premium-plugins/writer-craft/mcp/dist/cli/ingest-session-text.d.ts.map +1 -0
- package/payload/premium-plugins/writer-craft/mcp/dist/cli/ingest-session-text.js +58 -0
- package/payload/premium-plugins/writer-craft/mcp/dist/cli/ingest-session-text.js.map +1 -0
- package/payload/premium-plugins/writer-craft/mcp/dist/index.d.ts.map +1 -1
- package/payload/premium-plugins/writer-craft/mcp/dist/index.js +113 -36
- package/payload/premium-plugins/writer-craft/mcp/dist/index.js.map +1 -1
- package/payload/premium-plugins/writer-craft/mcp/dist/lib/voice-corpus.d.ts +47 -6
- package/payload/premium-plugins/writer-craft/mcp/dist/lib/voice-corpus.d.ts.map +1 -1
- package/payload/premium-plugins/writer-craft/mcp/dist/lib/voice-corpus.js +69 -6
- package/payload/premium-plugins/writer-craft/mcp/dist/lib/voice-corpus.js.map +1 -1
- package/payload/premium-plugins/writer-craft/mcp/dist/tools/voice-distil-profile.d.ts +9 -3
- package/payload/premium-plugins/writer-craft/mcp/dist/tools/voice-distil-profile.d.ts.map +1 -1
- package/payload/premium-plugins/writer-craft/mcp/dist/tools/voice-distil-profile.js +86 -57
- package/payload/premium-plugins/writer-craft/mcp/dist/tools/voice-distil-profile.js.map +1 -1
- package/payload/premium-plugins/writer-craft/mcp/dist/tools/voice-ingest-session-text.d.ts +23 -0
- package/payload/premium-plugins/writer-craft/mcp/dist/tools/voice-ingest-session-text.d.ts.map +1 -0
- package/payload/premium-plugins/writer-craft/mcp/dist/tools/voice-ingest-session-text.js +191 -0
- package/payload/premium-plugins/writer-craft/mcp/dist/tools/voice-ingest-session-text.js.map +1 -0
- package/payload/premium-plugins/writer-craft/mcp/dist/tools/voice-record-feedback.d.ts +7 -1
- package/payload/premium-plugins/writer-craft/mcp/dist/tools/voice-record-feedback.d.ts.map +1 -1
- package/payload/premium-plugins/writer-craft/mcp/dist/tools/voice-record-feedback.js +20 -12
- package/payload/premium-plugins/writer-craft/mcp/dist/tools/voice-record-feedback.js.map +1 -1
- package/payload/premium-plugins/writer-craft/mcp/dist/tools/voice-retrieve-conditioning.d.ts +13 -2
- package/payload/premium-plugins/writer-craft/mcp/dist/tools/voice-retrieve-conditioning.d.ts.map +1 -1
- package/payload/premium-plugins/writer-craft/mcp/dist/tools/voice-retrieve-conditioning.js +26 -15
- package/payload/premium-plugins/writer-craft/mcp/dist/tools/voice-retrieve-conditioning.js.map +1 -1
- package/payload/premium-plugins/writer-craft/mcp/dist/tools/voice-tag-content.d.ts +3 -0
- package/payload/premium-plugins/writer-craft/mcp/dist/tools/voice-tag-content.d.ts.map +1 -1
- package/payload/premium-plugins/writer-craft/mcp/dist/tools/voice-tag-content.js +33 -5
- package/payload/premium-plugins/writer-craft/mcp/dist/tools/voice-tag-content.js.map +1 -1
- package/payload/premium-plugins/writer-craft/mcp/scripts/smoke.mjs +289 -28
- package/payload/premium-plugins/writer-craft/mcp/src/cli/ingest-session-text.ts +65 -0
- package/payload/premium-plugins/writer-craft/mcp/src/index.ts +126 -36
- package/payload/premium-plugins/writer-craft/mcp/src/lib/voice-corpus.ts +78 -6
- package/payload/premium-plugins/writer-craft/mcp/src/tools/voice-distil-profile.ts +120 -61
- package/payload/premium-plugins/writer-craft/mcp/src/tools/voice-ingest-session-text.ts +229 -0
- package/payload/premium-plugins/writer-craft/mcp/src/tools/voice-record-feedback.ts +27 -13
- package/payload/premium-plugins/writer-craft/mcp/src/tools/voice-retrieve-conditioning.ts +42 -17
- package/payload/premium-plugins/writer-craft/mcp/src/tools/voice-tag-content.ts +42 -5
- package/payload/premium-plugins/writer-craft/skills/voice-mirror/SKILL.md +65 -31
- package/payload/server/server.js +12 -3
package/dist/index.js
CHANGED
|
@@ -3781,7 +3781,18 @@ try {
|
|
|
3781
3781
|
console.log("");
|
|
3782
3782
|
console.log("================================================================");
|
|
3783
3783
|
console.log("");
|
|
3784
|
-
|
|
3784
|
+
if (isLinux()) {
|
|
3785
|
+
console.log(` Same network (Pi / LAN): http://${DEVICE_HOSTNAME}.local:${PORT}`);
|
|
3786
|
+
console.log("");
|
|
3787
|
+
console.log(` Remote access (Hetzner / cloud) — on your local machine run:`);
|
|
3788
|
+
console.log(` ssh -L ${PORT}:localhost:${PORT} -L ${BRAND.websockifyPort}:localhost:${BRAND.websockifyPort} admin@<server-ipv4>`);
|
|
3789
|
+
console.log(` Then open:`);
|
|
3790
|
+
console.log(` Dashboard: http://localhost:${PORT}`);
|
|
3791
|
+
console.log(` VNC browser (Claude OAuth + Cloudflare): http://localhost:${BRAND.websockifyPort}/vnc.html`);
|
|
3792
|
+
}
|
|
3793
|
+
else {
|
|
3794
|
+
console.log(` Open in your browser: http://${DEVICE_HOSTNAME}.local:${PORT}`);
|
|
3795
|
+
}
|
|
3785
3796
|
console.log("");
|
|
3786
3797
|
console.log("================================================================");
|
|
3787
3798
|
}
|
package/package.json
CHANGED
|
@@ -1279,13 +1279,17 @@ CREATE INDEX postal_address_postcode IF NOT EXISTS
|
|
|
1279
1279
|
FOR (a:PostalAddress) ON (a.postalCode);
|
|
1280
1280
|
|
|
1281
1281
|
// ----------------------------------------------------------
|
|
1282
|
-
// Voice Mirror (Task 356) — authorial-voice capture + application
|
|
1282
|
+
// Voice Mirror (Task 356 + Task 462) — authorial-voice capture + application
|
|
1283
1283
|
// ----------------------------------------------------------
|
|
1284
|
-
// :VoiceProfile holds the distilled style card for one
|
|
1285
|
-
//
|
|
1284
|
+
// :VoiceProfile holds the distilled style card for one (AdminUser, format).
|
|
1285
|
+
// Task 462: one profile per (accountId, userId, format); format ∈
|
|
1286
|
+
// {text, email, social-post, article, marketing-copy, note}.
|
|
1287
|
+
// The old (accountId, adminUserId) unique constraint is dropped and replaced.
|
|
1288
|
+
//
|
|
1286
1289
|
// :VoiceEdit captures operator edits on agent drafts as feedback,
|
|
1287
1290
|
// stamped with a Haiku-summarised intent; many edits feed back into
|
|
1288
|
-
// the next distillation.
|
|
1291
|
+
// the next distillation. VoiceEdit now carries `format` to route
|
|
1292
|
+
// FEEDBACK_FOR edges to the matching per-format :VoiceProfile.
|
|
1289
1293
|
//
|
|
1290
1294
|
// `authorshipMode` is an enum property on content-bearing labels
|
|
1291
1295
|
// (`:KnowledgeDocument`, `:ConversationArchive` (Task 397 — every chat
|
|
@@ -1293,30 +1297,62 @@ FOR (a:PostalAddress) ON (a.postalCode);
|
|
|
1293
1297
|
// `:Message`, `:SocialPost`) with
|
|
1294
1298
|
// values `human-only | human-led-agent-assisted | agent-led-human-reviewed
|
|
1295
1299
|
// | agent-only | unknown`. Legacy nodes default to `unknown` until
|
|
1296
|
-
// reviewed via the voice-mirror backfill flow. The
|
|
1297
|
-
// distillation walk filter
|
|
1300
|
+
// reviewed via the voice-mirror backfill flow. The per-label authorship
|
|
1301
|
+
// index lets the distillation walk filter cheaply.
|
|
1302
|
+
//
|
|
1303
|
+
// `format` is an enum property on corpus nodes (same label set) and on
|
|
1304
|
+
// :VoiceProfile nodes. The per-label format index lets per-format corpus
|
|
1305
|
+
// walks and profile reads avoid full-label scans.
|
|
1306
|
+
|
|
1307
|
+
// Task 462 — drop the old (accountId, adminUserId) constraint before
|
|
1308
|
+
// creating the new (accountId, userId, format) three-key constraint.
|
|
1309
|
+
// `IF EXISTS` makes the DROP idempotent on fresh installs.
|
|
1310
|
+
DROP CONSTRAINT voice_profile_admin_unique IF EXISTS;
|
|
1298
1311
|
|
|
1299
|
-
CREATE CONSTRAINT
|
|
1300
|
-
FOR (v:VoiceProfile) REQUIRE (v.accountId, v.
|
|
1312
|
+
CREATE CONSTRAINT voice_profile_format_unique IF NOT EXISTS
|
|
1313
|
+
FOR (v:VoiceProfile) REQUIRE (v.accountId, v.userId, v.format) IS UNIQUE;
|
|
1301
1314
|
|
|
1302
1315
|
CREATE INDEX voice_profile_account IF NOT EXISTS
|
|
1303
1316
|
FOR (v:VoiceProfile) ON (v.accountId);
|
|
1304
1317
|
|
|
1305
|
-
CREATE INDEX
|
|
1306
|
-
FOR (
|
|
1318
|
+
CREATE INDEX voice_profile_format IF NOT EXISTS
|
|
1319
|
+
FOR (v:VoiceProfile) ON (v.format);
|
|
1320
|
+
|
|
1321
|
+
CREATE INDEX voice_edit_user IF NOT EXISTS
|
|
1322
|
+
FOR (e:VoiceEdit) ON (e.userId);
|
|
1307
1323
|
|
|
1308
1324
|
CREATE INDEX knowledge_document_authorship IF NOT EXISTS
|
|
1309
1325
|
FOR (k:KnowledgeDocument) ON (k.authorshipMode);
|
|
1310
1326
|
|
|
1327
|
+
CREATE INDEX knowledge_document_format IF NOT EXISTS
|
|
1328
|
+
FOR (k:KnowledgeDocument) ON (k.format);
|
|
1329
|
+
|
|
1311
1330
|
CREATE INDEX conversation_archive_authorship IF NOT EXISTS
|
|
1312
1331
|
FOR (c:ConversationArchive) ON (c.authorshipMode);
|
|
1313
1332
|
|
|
1333
|
+
CREATE INDEX conversation_archive_format IF NOT EXISTS
|
|
1334
|
+
FOR (c:ConversationArchive) ON (c.format);
|
|
1335
|
+
|
|
1314
1336
|
CREATE INDEX message_authorship IF NOT EXISTS
|
|
1315
1337
|
FOR (m:Message) ON (m.authorshipMode);
|
|
1316
1338
|
|
|
1339
|
+
CREATE INDEX message_format IF NOT EXISTS
|
|
1340
|
+
FOR (m:Message) ON (m.format);
|
|
1341
|
+
|
|
1342
|
+
// contentHash index — deduplication MERGE in voice-ingest-session-text uses
|
|
1343
|
+
// MERGE (n:Message {contentHash: $hash, accountId: $accountId}). Without this
|
|
1344
|
+
// index, each MERGE scans all :Message nodes for the account. The index on
|
|
1345
|
+
// contentHash alone lets neo4j narrow the lookup before applying the
|
|
1346
|
+
// accountId predicate.
|
|
1347
|
+
CREATE INDEX message_content_hash IF NOT EXISTS
|
|
1348
|
+
FOR (m:Message) ON (m.contentHash);
|
|
1349
|
+
|
|
1317
1350
|
CREATE INDEX social_post_authorship IF NOT EXISTS
|
|
1318
1351
|
FOR (s:SocialPost) ON (s.authorshipMode);
|
|
1319
1352
|
|
|
1353
|
+
CREATE INDEX social_post_format IF NOT EXISTS
|
|
1354
|
+
FOR (s:SocialPost) ON (s.format);
|
|
1355
|
+
|
|
1320
1356
|
// :Section authorshipMode — the corpus walk includes conversation-archive
|
|
1321
1357
|
// :Section chunks (parent :ConversationArchive) alongside ordinary
|
|
1322
1358
|
// document sections under :KnowledgeDocument. Index on the :Section label
|
|
@@ -1325,6 +1361,9 @@ FOR (s:SocialPost) ON (s.authorshipMode);
|
|
|
1325
1361
|
CREATE INDEX section_authorship IF NOT EXISTS
|
|
1326
1362
|
FOR (s:Section) ON (s.authorshipMode);
|
|
1327
1363
|
|
|
1364
|
+
CREATE INDEX section_format IF NOT EXISTS
|
|
1365
|
+
FOR (s:Section) ON (s.format);
|
|
1366
|
+
|
|
1328
1367
|
CREATE INDEX social_post_account IF NOT EXISTS
|
|
1329
1368
|
FOR (s:SocialPost) ON (s.accountId);
|
|
1330
1369
|
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
## What It Does
|
|
4
4
|
|
|
5
|
-
{{productName}} reads emails, posts, and
|
|
5
|
+
{{productName}} 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.
|
|
6
6
|
|
|
7
7
|
Anthropic models cannot be fine-tuned. Voice mirror works by feeding the model two things alongside every drafting task:
|
|
8
8
|
|
|
@@ -11,32 +11,34 @@ Anthropic models cannot be fine-tuned. Voice mirror works by feeding the model t
|
|
|
11
11
|
|
|
12
12
|
The model conditions on both and produces copy that reads as yours.
|
|
13
13
|
|
|
14
|
-
|
|
14
|
+
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.
|
|
15
15
|
|
|
16
|
-
|
|
16
|
+
## How Your Voice Is Captured
|
|
17
17
|
|
|
18
|
-
|
|
18
|
+
### Automatically — from chat
|
|
19
|
+
|
|
20
|
+
Every admin chat session feeds your writing into the `text` profile automatically. When the session ends, {{productName}} 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.
|
|
21
|
+
|
|
22
|
+
### Via backfill — from historical content
|
|
23
|
+
|
|
24
|
+
Use the backfill flow to teach {{productName}} your writing from emails, documents, and social posts you've already written.
|
|
19
25
|
|
|
20
26
|
In the admin chat, ask: **"Start the voice-mirror backfill."**
|
|
21
27
|
|
|
22
28
|
{{productName}} 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.
|
|
23
29
|
|
|
24
30
|
- **Chat archives** — tag a whole conversation in one click. {{productName}} 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).
|
|
25
|
-
- **Documents and posts** — paginated 10 at a time. 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, {{productName}} polished).
|
|
31
|
+
- **Documents and posts** — paginated 10 at a time. {{productName}} 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, {{productName}} polished). Override the detected format if one is wrong.
|
|
26
32
|
|
|
27
33
|
Skip a batch if none qualify, or stop at any time — the next session resumes where you left off.
|
|
28
34
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
Once you have at least ~20 `human-only` items tagged, ask: **"Build my voice profile."**
|
|
32
|
-
|
|
33
|
-
{{productName}} reads the corpus, 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.
|
|
35
|
+
## Distilling Your Profile
|
|
34
36
|
|
|
35
|
-
|
|
37
|
+
Once you have corpus entries tagged (or after automatic PTY ingestion fills the `text` profile), ask: **"Build my voice profile."**
|
|
36
38
|
|
|
37
|
-
|
|
39
|
+
{{productName}} 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.
|
|
38
40
|
|
|
39
|
-
|
|
41
|
+
The profile re-runs automatically when your corpus grows by ≥20% for any format or every 30 days, whichever comes first.
|
|
40
42
|
|
|
41
43
|
## Feedback Loop
|
|
42
44
|
|
|
@@ -50,11 +52,11 @@ Voice mirror is on by default for every drafting skill. To opt out for one, set
|
|
|
50
52
|
|
|
51
53
|
## What It Won't Do
|
|
52
54
|
|
|
53
|
-
- **Blend voices** — one profile per person, no "Joel + Neo combined".
|
|
55
|
+
- **Blend voices** — one profile set per person, no "Joel + Neo combined".
|
|
54
56
|
- **Copy public figures** — voice mirror only learns from your own writing.
|
|
55
57
|
- **Clone audio** — text only, no speech synthesis.
|
|
56
|
-
- **Guess** — content stays `unknown` until you mark it. {{productName}} never auto-classifies your
|
|
58
|
+
- **Guess** — historical content stays `unknown` until you mark it. {{productName}} never auto-classifies your writing. (Automatic ingestion applies only to your live PTY sessions where authorship is certain.)
|
|
57
59
|
|
|
58
60
|
## Status
|
|
59
61
|
|
|
60
|
-
Voice mirror
|
|
62
|
+
Voice mirror is live end-to-end. Six corpus formats (text, email, social-post, article, note, marketing-copy), five tools (`voice-tag-content`, `voice-distil-profile`, `voice-retrieve-conditioning`, `voice-record-feedback`, `voice-ingest-session-text`), automatic PTY-turn ingestion via SessionEnd hook, and wiring into the three live drafting surfaces (email composition, property brochures, investor data room) are all live. When no voice profile exists on the account for a given format, every drafting skill degrades gracefully — the output matches what it was before voice mirror was installed.
|
|
@@ -58,6 +58,7 @@ mkdir -p "$ACCOUNT_DIR/agents/admin" "$ACCOUNT_DIR/agents/public" "$ACCOUNT_DIR/
|
|
|
58
58
|
# to locate scripts relative to the platform installation, not the account dir.
|
|
59
59
|
ACCOUNT_SETTINGS="$ACCOUNT_DIR/.claude/settings.json"
|
|
60
60
|
HOOKS_PATH="\$PLATFORM_ROOT/plugins/admin/hooks"
|
|
61
|
+
WRITER_CRAFT_HOOKS_PATH="\$PLATFORM_ROOT/../premium-plugins/writer-craft/hooks"
|
|
61
62
|
cat > "$ACCOUNT_SETTINGS" << SETTINGS_EOF
|
|
62
63
|
{
|
|
63
64
|
"hooks": {
|
|
@@ -146,6 +147,13 @@ cat > "$ACCOUNT_SETTINGS" << SETTINGS_EOF
|
|
|
146
147
|
{ "type": "command", "command": "bash $HOOKS_PATH/session-end-retrospective.sh" }
|
|
147
148
|
]
|
|
148
149
|
}
|
|
150
|
+
],
|
|
151
|
+
"SessionEnd": [
|
|
152
|
+
{
|
|
153
|
+
"hooks": [
|
|
154
|
+
{ "type": "command", "command": "bash $WRITER_CRAFT_HOOKS_PATH/voice-session-end-text.sh" }
|
|
155
|
+
]
|
|
156
|
+
}
|
|
149
157
|
]
|
|
150
158
|
}
|
|
151
159
|
}
|
|
@@ -68,6 +68,13 @@ ADMIN_OWNED_SKILLS = {
|
|
|
68
68
|
"memory/conversational-memory",
|
|
69
69
|
}
|
|
70
70
|
|
|
71
|
+
# Regex for skill-name tokens in the prompt body that require `Skill` in tools:
|
|
72
|
+
# 1. `skill-load skillName=<name>` pattern (how templates reference Skill calls)
|
|
73
|
+
# 2. `Skill <name>` pattern (explicit Skill tool invocation in enforcement directives)
|
|
74
|
+
# Only hyphenated lowercase names are skill names.
|
|
75
|
+
SKILL_LOAD_RE = re.compile(r"skillName=([a-z][a-z0-9-]+)")
|
|
76
|
+
SKILL_INVOKE_RE = re.compile(r"`Skill\s+([a-z][a-z0-9-]+)`")
|
|
77
|
+
|
|
71
78
|
TOKEN_RE = re.compile(r"`(mcp__[a-z][a-z0-9_-]*__[a-z][a-z0-9_-]*)`")
|
|
72
79
|
FENCED_BLOCK_RE = re.compile(r"```(?P<lang>[a-zA-Z]*)\n(?P<body>.*?)\n```", re.S)
|
|
73
80
|
PROSE_CYPHER_RE = re.compile(
|
|
@@ -170,6 +177,73 @@ def aggregate_skill_text(skill_dir: str) -> str:
|
|
|
170
177
|
return "\n".join(out)
|
|
171
178
|
|
|
172
179
|
|
|
180
|
+
def collect_skill_names() -> set[str]:
|
|
181
|
+
"""Enumerate all installed skill directory names from platform/plugins/*/skills/."""
|
|
182
|
+
names: set[str] = set()
|
|
183
|
+
if not os.path.isdir(PLUGINS_DIR):
|
|
184
|
+
return names
|
|
185
|
+
for plugin in os.listdir(PLUGINS_DIR):
|
|
186
|
+
skills_dir = os.path.join(PLUGINS_DIR, plugin, "skills")
|
|
187
|
+
if not os.path.isdir(skills_dir):
|
|
188
|
+
continue
|
|
189
|
+
for entry in os.listdir(skills_dir):
|
|
190
|
+
if os.path.isdir(os.path.join(skills_dir, entry)):
|
|
191
|
+
names.add(entry)
|
|
192
|
+
return names
|
|
193
|
+
|
|
194
|
+
|
|
195
|
+
def specialist_body(specialist_path: str) -> str:
|
|
196
|
+
"""Return the prompt body of a specialist template (content below frontmatter)."""
|
|
197
|
+
try:
|
|
198
|
+
text = open(specialist_path, encoding="utf-8").read()
|
|
199
|
+
except FileNotFoundError:
|
|
200
|
+
return ""
|
|
201
|
+
m = re.match(r"^---\n.*?\n---\n(.*)", text, re.S)
|
|
202
|
+
return m.group(1) if m else text
|
|
203
|
+
|
|
204
|
+
|
|
205
|
+
def check_builtin_tool_rule(
|
|
206
|
+
specialist: str,
|
|
207
|
+
body: str,
|
|
208
|
+
tools: set[str],
|
|
209
|
+
known_skills: set[str],
|
|
210
|
+
) -> list[str]:
|
|
211
|
+
"""Built-in-tool rule: if the specialist prompt references a skill load that
|
|
212
|
+
matches an installed skill directory, `Skill` must appear in tools:."""
|
|
213
|
+
referenced: set[str] = set()
|
|
214
|
+
# Pattern 1: skill-load skillName=<name> (template invocation form)
|
|
215
|
+
referenced |= set(SKILL_LOAD_RE.findall(body)) & known_skills
|
|
216
|
+
# Pattern 2: `Skill <name>` (enforcement directive form)
|
|
217
|
+
referenced |= set(SKILL_INVOKE_RE.findall(body)) & known_skills
|
|
218
|
+
if not referenced or "Skill" in tools:
|
|
219
|
+
return []
|
|
220
|
+
return [
|
|
221
|
+
f"[verify] specialist={specialist} claims-loads={name} "
|
|
222
|
+
f"but Skill missing from tools"
|
|
223
|
+
for name in sorted(referenced)
|
|
224
|
+
]
|
|
225
|
+
|
|
226
|
+
|
|
227
|
+
def check_webfetch_rule(
|
|
228
|
+
specialist: str,
|
|
229
|
+
body: str,
|
|
230
|
+
tools: set[str],
|
|
231
|
+
) -> list[str]:
|
|
232
|
+
"""WebFetch rule: if the specialist prompt names WebFetch explicitly or
|
|
233
|
+
directs dereferencing an operator-provided URL, WebFetch must be in tools:."""
|
|
234
|
+
if "WebFetch" in tools:
|
|
235
|
+
return []
|
|
236
|
+
has_webfetch = bool(re.search(r"\bWebFetch\b", body))
|
|
237
|
+
has_fetch_url = bool(re.search(r"\bfetch\b.*\bURL\b", body, re.IGNORECASE))
|
|
238
|
+
if not (has_webfetch or has_fetch_url):
|
|
239
|
+
return []
|
|
240
|
+
reason = "WebFetch" if has_webfetch else r"\bfetch\b.*\bURL\b"
|
|
241
|
+
return [
|
|
242
|
+
f"[verify] specialist={specialist} directs WebFetch but tool missing "
|
|
243
|
+
f"(matched: {reason})"
|
|
244
|
+
]
|
|
245
|
+
|
|
246
|
+
|
|
173
247
|
def main() -> int:
|
|
174
248
|
if not os.path.isdir(PLUGINS_DIR):
|
|
175
249
|
print(f"[verify] PLUGINS_DIR not found: {PLUGINS_DIR}", file=sys.stderr)
|
|
@@ -252,6 +326,49 @@ def main() -> int:
|
|
|
252
326
|
)
|
|
253
327
|
pairs_checked += 1
|
|
254
328
|
|
|
329
|
+
# Built-in-tool rule + WebFetch rule: sweep all agent template .md files.
|
|
330
|
+
# Covers platform specialists (SPECIALISTS_DIR) and premium-plugin agent
|
|
331
|
+
# templates (premium-plugins/*/agents/). These rules are orthogonal to the
|
|
332
|
+
# skill-pairing loop above — they check each agent's own prompt body for
|
|
333
|
+
# directives that require built-in CC tools.
|
|
334
|
+
known_skills = collect_skill_names()
|
|
335
|
+
builtin_checked = 0
|
|
336
|
+
|
|
337
|
+
agent_template_dirs: list[str] = []
|
|
338
|
+
if os.path.isdir(SPECIALISTS_DIR):
|
|
339
|
+
agent_template_dirs.append(SPECIALISTS_DIR)
|
|
340
|
+
pp_root = os.path.join(REPO_ROOT, "premium-plugins")
|
|
341
|
+
if os.path.isdir(pp_root):
|
|
342
|
+
for plugin in sorted(os.listdir(pp_root)):
|
|
343
|
+
adir = os.path.join(pp_root, plugin, "agents")
|
|
344
|
+
if os.path.isdir(adir):
|
|
345
|
+
agent_template_dirs.append(adir)
|
|
346
|
+
|
|
347
|
+
for adir in agent_template_dirs:
|
|
348
|
+
for fname in sorted(os.listdir(adir)):
|
|
349
|
+
if not fname.endswith(".md"):
|
|
350
|
+
continue
|
|
351
|
+
spath = os.path.join(adir, fname)
|
|
352
|
+
fm = parse_frontmatter(spath)
|
|
353
|
+
if fm is None:
|
|
354
|
+
continue
|
|
355
|
+
specialist = fm.get("name") or fname[:-3]
|
|
356
|
+
raw = fm.get("tools", "")
|
|
357
|
+
if isinstance(raw, list):
|
|
358
|
+
tools = {t for t in raw if t}
|
|
359
|
+
else:
|
|
360
|
+
tools = {t.strip() for t in str(raw).split(",") if t.strip()}
|
|
361
|
+
body = specialist_body(spath)
|
|
362
|
+
for err in check_builtin_tool_rule(specialist, body, tools, known_skills):
|
|
363
|
+
errors.append(err)
|
|
364
|
+
for err in check_webfetch_rule(specialist, body, tools):
|
|
365
|
+
errors.append(err)
|
|
366
|
+
builtin_checked += 1
|
|
367
|
+
|
|
368
|
+
summary.append(
|
|
369
|
+
f"[verify] builtin-tool-check specialists_checked={builtin_checked}"
|
|
370
|
+
)
|
|
371
|
+
|
|
255
372
|
for line in summary:
|
|
256
373
|
print(line)
|
|
257
374
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"specialist-drift.d.ts","sourceRoot":"","sources":["../src/specialist-drift.ts"],"names":[],"mappings":"AA4BA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAA;
|
|
1
|
+
{"version":3,"file":"specialist-drift.d.ts","sourceRoot":"","sources":["../src/specialist-drift.ts"],"names":[],"mappings":"AA4BA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAA;AAoCpD,MAAM,WAAW,qBAAqB;IACpC,cAAc,EAAE,MAAM,CAAA;IACtB,cAAc,EAAE,MAAM,CAAA;IACtB,IAAI,EAAE,MAAM,CAAA;IACZ,MAAM,EACF,0BAA0B,GAC1B,wBAAwB,GACxB,gBAAgB,GAChB,uBAAuB,CAAA;CAC5B;AAED,MAAM,WAAW,qBAAqB;IACpC;;;yCAGqC;IACrC,EAAE,EAAE,OAAO,CAAA;IACX;;wCAEoC;IACpC,OAAO,EAAE,qBAAqB,EAAE,CAAA;IAChC,2EAA2E;IAC3E,SAAS,EAAE,MAAM,CAAA;IACjB;;;;6CAIyC;IACzC,SAAS,EAAE,WAAW,CAAC,MAAM,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC,CAAA;CACpD;AAED;;;kEAGkE;AAClE,wBAAgB,wBAAwB,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAI3E;AAmCD;;;;;;;;;wDASwD;AACxD,wBAAgB,qBAAqB,CACnC,SAAS,EAAE,SAAS,MAAM,EAAE,EAC5B,WAAW,EAAE,WAAW,EACxB,eAAe,GAAE,WAAW,CAAC,MAAM,CAAa,GAC/C,qBAAqB,CAgDvB"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"specialist-drift.js","sourceRoot":"","sources":["../src/specialist-drift.ts"],"names":[],"mappings":"AAAA,kEAAkE;AAClE,EAAE;AACF,wEAAwE;AACxE,qEAAqE;AACrE,wEAAwE;AACxE,yEAAyE;AACzE,wEAAwE;AACxE,uEAAuE;AACvE,wBAAwB;AACxB,EAAE;AACF,qEAAqE;AACrE,wEAAwE;AACxE,EAAE;AACF,6DAA6D;AAC7D,yEAAyE;AACzE,gEAAgE;AAChE,wCAAwC;AACxC,4EAA4E;AAC5E,gDAAgD;AAChD,EAAE;AACF,0EAA0E;AAC1E,sEAAsE;AACtE,wEAAwE;AACxE,uEAAuE;AACvE,sBAAsB;AAEtB,OAAO,EAAE,YAAY,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAA;AAC7D,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAA;AAG1C;;sDAEsD;AACtD,MAAM,eAAe,GAAG,IAAI,GAAG,CAAS;IACtC,MAAM;IACN,OAAO;IACP,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,YAAY;IACZ,WAAW;IACX,WAAW;IACX,UAAU;IACV,MAAM;IACN,WAAW;IACX,cAAc;IACd,cAAc;IACd,iBAAiB;CAClB,CAAC,CAAA;AAEF;;;;;;;;;wDASwD;AACxD,MAAM,eAAe,GAAG,CAAC,cAAc,EAAE,cAAc,CAAC,CAAA;AAiCxD;;;kEAGkE;AAClE,MAAM,UAAU,wBAAwB,CAAC,WAAmB;IAC1D,MAAM,CAAC,GAAG,WAAW,CAAC,KAAK,CAAC,kBAAkB,CAAC,CAAA;IAC/C,IAAI,CAAC,CAAC;QAAE,OAAO,IAAI,CAAA;IACnB,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAA;AACpB,CAAC;AAED,SAAS,aAAa,CAAC,GAAW;IAChC,OAAO,GAAG;SACP,KAAK,CAAC,GAAG,CAAC;SACV,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;SACpB,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,CAAA;AAChC,CAAC;AAED,SAAS,YAAY,CACnB,IAAY,EACZ,MAA2B,EAC3B,eAAoC;IAEpC,IAAI,eAAe,CAAC,GAAG,CAAC,IAAI,CAAC;QAAE,OAAO,IAAI,CAAA;IAC1C,KAAK,MAAM,MAAM,IAAI,eAAe,EAAE,CAAC;QACrC,IAAI,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC;YAAE,OAAO,IAAI,CAAA;IAC1C,CAAC;IACD,IAAI,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC;QAAE,OAAO,IAAI,CAAA;IACjC,MAAM,QAAQ,GAAG,IAAI,CAAC,KAAK,CAAC,4BAA4B,CAAC,CAAA;IACzD,IAAI,CAAC,QAAQ;QAAE,OAAO,gBAAgB,CAAA;IACtC,MAAM,EAAE,GAAG,QAAQ,CAAC,CAAC,CAAC,CAAA;IACtB,uEAAuE;IACvE,qEAAqE;IACrE,sEAAsE;IACtE,MAAM,YAAY,GAAG,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,UAAU,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC,CAAA;IACjF,IAAI,YAAY;QAAE,OAAO,wBAAwB,CAAA;IACjD,iEAAiE;IACjE,uEAAuE;IACvE,mEAAmE;IACnE,iDAAiD;IACjD,IAAI,eAAe,CAAC,GAAG,CAAC,EAAE,CAAC;QAAE,OAAO,uBAAuB,CAAA;IAC3D,OAAO,0BAA0B,CAAA;AACnC,CAAC;AAED;;;;;;;;;wDASwD;AACxD,MAAM,UAAU,qBAAqB,CACnC,SAA4B,EAC5B,WAAwB,EACxB,kBAAuC,IAAI,GAAG,EAAE;IAEhD,MAAM,OAAO,GAA4B,EAAE,CAAA;IAC3C,MAAM,SAAS,GAAG,IAAI,GAAG,EAAuB,CAAA;IAChD,IAAI,SAAS,GAAG,CAAC,CAAA;IACjB,KAAK,MAAM,GAAG,IAAI,SAAS,EAAE,CAAC;QAC5B,IAAI,OAAiB,CAAA;QACrB,IAAI,CAAC;YAAC,OAAO,GAAG,WAAW,CAAC,GAAG,CAAC,CAAA;QAAC,CAAC;QAAC,MAAM,CAAC;YAAC,SAAQ;QAAC,CAAC;QACrD,KAAK,MAAM,KAAK,IAAI,OAAO,CAAC,IAAI,EAAE,EAAE,CAAC;YACnC,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,EAAE,KAAK,CAAC,CAAA;YACjC,IAAI,EAA+B,CAAA;YACnC,IAAI,CAAC;gBAAC,EAAE,GAAG,QAAQ,CAAC,QAAQ,CAAC,CAAA;YAAC,CAAC;YAAC,MAAM,CAAC;gBAAC,SAAQ;YAAC,CAAC;YAClD,IAAI,CAAC,EAAE,CAAC,MAAM,EAAE;gBAAE,SAAQ;YAC1B,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC;gBAAE,SAAQ;YACpC,sEAAsE;YACtE,mEAAmE;YACnE,mEAAmE;YACnE,mEAAmE;YACnE,oDAAoD;YACpD,MAAM,aAAa,GAAG,QAAQ,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC,WAAW,EAAE,CAAA;YAC1D,IAAI,aAAa,KAAK,UAAU,IAAI,aAAa,KAAK,MAAM,IAAI,aAAa,KAAK,QAAQ,IAAI,aAAa,KAAK,WAAW;gBAAE,SAAQ;YACrI,MAAM,GAAG,GAAG,YAAY,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAA;YAC3C,MAAM,OAAO,GAAG,GAAG,CAAC,KAAK,CAAC,6BAA6B,CAAC,CAAA;YACxD,IAAI,CAAC,OAAO;gBAAE,SAAQ;YACtB,MAAM,SAAS,GAAG,wBAAwB,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAA;YACtD,IAAI,CAAC,SAAS;gBAAE,SAAQ;YACxB,SAAS,IAAI,CAAC,CAAA;YACd,MAAM,cAAc,GAAG,QAAQ,CAAC,KAAK,EAAE,KAAK,CAAC,CAAA;YAC7C,KAAK,MAAM,IAAI,IAAI,aAAa,CAAC,SAAS,CAAC,EAAE,CAAC;gBAC5C,MAAM,OAAO,GAAG,YAAY,CAAC,IAAI,EAAE,WAAW,CAAC,GAAG,EAAE,eAAe,CAAC,CAAA;gBACpE,IAAI,OAAO,KAAK,IAAI;oBAAE,SAAQ;gBAC9B,OAAO,CAAC,IAAI,CAAC,EAAE,cAAc,EAAE,QAAQ,EAAE,cAAc,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC,CAAA;gBACjF,IAAI,OAAO,KAAK,uBAAuB,EAAE,CAAC;oBACxC,IAAI,GAAG,GAAG,SAAS,CAAC,GAAG,CAAC,cAAc,CAAC,CAAA;oBACvC,IAAI,CAAC,GAAG,EAAE,CAAC;wBACT,GAAG,GAAG,IAAI,GAAG,EAAE,CAAA;wBACf,SAAS,CAAC,GAAG,CAAC,cAAc,EAAE,GAAG,CAAC,CAAA;oBACpC,CAAC;oBACD,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,CAAA;gBACf,CAAC;YACH,CAAC;QACH,CAAC;IACH,CAAC;IACD,kEAAkE;IAClE,uEAAuE;IACvE,uEAAuE;IACvE,6CAA6C;IAC7C,MAAM,EAAE,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,KAAK,uBAAuB,CAAC,CAAA;IACrE,OAAO,EAAE,EAAE,EAAE,OAAO,EAAE,SAAS,EAAE,SAAS,EAAE,CAAA;AAC9C,CAAC"}
|
|
1
|
+
{"version":3,"file":"specialist-drift.js","sourceRoot":"","sources":["../src/specialist-drift.ts"],"names":[],"mappings":"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"}
|
|
@@ -3,7 +3,7 @@ name: content-producer
|
|
|
3
3
|
description: "Visual production and static-site hosting. Reads from the populated graph to produce visual artifacts (image generation, PDF rendering, component delivery) and hosts already-prepared static sites by extracting attached archives via unzip-attachment then placing the tree under <accountDir>/sites/<slug>/ via publish-site. Delegate for: generating images, saving rendered pages as PDF, or any 'host this website' / 'publish this site' / 'put this online' intent carrying an HTML+assets archive. Not document ingestion: graph ingestion of any kind routes to specialists:database-operator. Static-site zips are extracted to disk for publication, never written to the graph."
|
|
4
4
|
summary: "Produces visual output from your graph: generates images, renders pages to PDF, and hosts static websites you upload as a zip."
|
|
5
5
|
model: claude-sonnet-4-6
|
|
6
|
-
tools: Bash, mcp__memory__memory-search, mcp__replicate__image-generate, mcp__plugin_playwright_playwright__browser_navigate, mcp__plugin_playwright_playwright__browser_snapshot, mcp__plugin_playwright_playwright__browser_take_screenshot, mcp__plugin_playwright_playwright__browser_pdf_save, mcp__admin__file-attach, mcp__admin__plugin-read, mcp__admin__public-hostname, mcp__admin__publish-site
|
|
6
|
+
tools: Bash, Skill, mcp__memory__memory-search, mcp__replicate__image-generate, mcp__plugin_playwright_playwright__browser_navigate, mcp__plugin_playwright_playwright__browser_snapshot, mcp__plugin_playwright_playwright__browser_take_screenshot, mcp__plugin_playwright_playwright__browser_pdf_save, mcp__admin__file-attach, mcp__admin__plugin-read, mcp__admin__public-hostname, mcp__admin__publish-site
|
|
7
7
|
---
|
|
8
8
|
|
|
9
9
|
# Content Producer
|
|
@@ -32,13 +32,13 @@ Three models via `image-generate`. Pick by output need: `recraft-v4` for design-
|
|
|
32
32
|
|
|
33
33
|
## PDF output
|
|
34
34
|
|
|
35
|
-
Generate the HTML, navigate the Playwright browser to it, and capture with `browser_pdf_save`. For A4 print,
|
|
35
|
+
Generate the HTML, navigate the Playwright browser to it, and capture with `browser_pdf_save`. For A4 print, **the first tool call of this workflow branch MUST be `Skill a4-print-documents`. Any browser tool call before the skill content is loaded into context is a contract violation.** Load `skill-load skillName=a4-print-documents`: the skill carries the print-CSS constraints (page margins, glassmorphism fallback, page-break rules, dark-background colour-adjust). Do not paraphrase those rules; load and follow.
|
|
36
36
|
|
|
37
37
|
`file://` URLs are rewritten transparently by the `playwright-file-guard` PreToolUse hook. Pass them directly to `browser_navigate`.
|
|
38
38
|
|
|
39
39
|
## Hosting websites
|
|
40
40
|
|
|
41
|
-
When a brief carries a "host this website" / "publish this site" / "put this online" intent with a `.zip` of HTML and assets,
|
|
41
|
+
When a brief carries a "host this website" / "publish this site" / "put this online" intent with a `.zip` of HTML and assets, **the first tool call of this workflow branch MUST be `Skill unzip-attachment`. Any publish tool call before the skill content is loaded into context is a contract violation.** Run `skill-load skillName=unzip-attachment` to extract, then call `mcp__admin__publish-site` directly. The tool owns slug validation, the symlink scan, the `mv`, the refusal taxonomy, and the post-publish llms.txt refresh — load `skill-load skillName=publish-site` only if you need the intent-router context. Do not improvise a fallback server.
|
|
42
42
|
|
|
43
43
|
Confirm the slug with the operator before publishing. The slug is one or more `/`-separated segments under `<accountDir>/sites/`. Refusals are loud-fail; relay the tool's `Operator action:` line verbatim and stop. On success, take the `pathSlug` from the tool response, call `mcp__admin__public-hostname`, and surface `https://<hostname><pathSlug>` to the operator as one line.
|
|
44
44
|
|
|
@@ -60,4 +60,4 @@ Return to the admin agent: what you did (images generated, PDFs produced, compon
|
|
|
60
60
|
|
|
61
61
|
## Plain English
|
|
62
62
|
|
|
63
|
-
Load `skill-load skillName=plainly` on the first turn and apply it to every prose payload returned to admin (captions, brochure prose, summaries, the "What you did" lines). It does not apply to `image-generate` prompts: those are agent-to-machine payloads where technical descriptors are required vocabulary, not jargon to strip.
|
|
63
|
+
**The first tool call MUST be `Skill plainly`. Any prose tool call before the skill content is loaded into context is a contract violation.** Load `skill-load skillName=plainly` on the first turn and apply it to every prose payload returned to admin (captions, brochure prose, summaries, the "What you did" lines). It does not apply to `image-generate` prompts: those are agent-to-machine payloads where technical descriptors are required vocabulary, not jargon to strip.
|
|
@@ -3,7 +3,7 @@ name: librarian
|
|
|
3
3
|
description: "Foreground ingester for the memory graph. Owns external-archive and document ingestion — PDFs, web pages, plain text, conversation transcripts (WhatsApp / Telegram / Signal / iMessage / Slack / LinkedIn DMs / Zoom / meeting minutes), LinkedIn Basic Data Exports, and post-unzip trees the admin agent forwards. Loads `document-ingest`, `conversation-archive`, `conversation-archive-enrich`, and `linkedin-import` skills. Returns to the admin agent with a structured outcome line; never interacts with the operator directly except through the dispatching agent."
|
|
4
4
|
summary: "Owns foreground ingest of documents, conversation transcripts, and external archives into the memory graph."
|
|
5
5
|
model: claude-sonnet-4-5
|
|
6
|
-
tools: mcp__plugin_memory_memory__memory-ingest-extract, mcp__plugin_memory_memory__memory-ingest, mcp__plugin_memory_memory__memory-ingest-web, mcp__plugin_memory_memory__memory-archive-write, mcp__plugin_memory_memory__memory-write, mcp__plugin_memory_memory__memory-update, mcp__plugin_memory_memory__memory-search, mcp__plugin_memory_memory__conversation-archive-list-chunks, mcp__plugin_memory_memory__conversation-archive-derive-insights, mcp__plugin_memory_memory__conversation-archive-enrich-rejection, mcp__plugin_contacts_contacts__contact-create, mcp__plugin_work_work__work-create, Read, Bash
|
|
6
|
+
tools: mcp__plugin_memory_memory__memory-ingest-extract, mcp__plugin_memory_memory__memory-ingest, mcp__plugin_memory_memory__memory-ingest-web, mcp__plugin_memory_memory__memory-archive-write, mcp__plugin_memory_memory__memory-write, mcp__plugin_memory_memory__memory-update, mcp__plugin_memory_memory__memory-search, mcp__plugin_memory_memory__conversation-archive-list-chunks, mcp__plugin_memory_memory__conversation-archive-derive-insights, mcp__plugin_memory_memory__conversation-archive-enrich-rejection, mcp__plugin_contacts_contacts__contact-create, mcp__plugin_work_work__work-create, Read, Bash, Skill, WebFetch
|
|
7
7
|
---
|
|
8
8
|
|
|
9
9
|
# Librarian
|
|
@@ -28,7 +28,7 @@ These three rules win when anything else in this prompt conflicts with them.
|
|
|
28
28
|
|
|
29
29
|
## Skill routing
|
|
30
30
|
|
|
31
|
-
The dispatch brief from the admin agent names the input class. Map it to one skill
|
|
31
|
+
The dispatch brief from the admin agent names the input class. Map it to one skill. **After routing, the first tool call MUST be `Skill <skill-name>`. Any `memory-*` write tool called before the skill content is loaded into context is a contract violation.**
|
|
32
32
|
|
|
33
33
|
| Input | Skill | Parent label |
|
|
34
34
|
|---|---|---|
|
|
@@ -3,7 +3,7 @@ name: personal-assistant
|
|
|
3
3
|
description: "Your personal assistant. Scheduling, platform administration, messaging channels (Telegram, WhatsApp, email, Outlook), system health, Cloudflare tunnel setup, and browser automation. Delegate when a task involves managing your calendar, configuring the platform, operating messaging channels, setting up a tunnel or domain, or completing interactive browser tasks."
|
|
4
4
|
summary: "Handles the operational tasks you'd give a personal assistant: scheduling meetings, managing your platform settings, connecting messaging channels, and completing browser-based tasks on your behalf."
|
|
5
5
|
model: claude-sonnet-4-6
|
|
6
|
-
tools: mcp__admin__system-status, mcp__admin__brand-settings, mcp__admin__account-manage, mcp__admin__account-update, mcp__admin__logs-read, mcp__admin__plugin-read, mcp__admin__file-attach, mcp__admin__wifi, mcp__contacts__contact-create, mcp__contacts__contact-lookup, mcp__contacts__contact-update, mcp__contacts__contact-delete, mcp__contacts__contact-list, mcp__contacts__contact-export, mcp__contacts__contact-erase, mcp__contacts__group-create, mcp__contacts__group-manage, mcp__telegram__message, mcp__telegram__message-history, mcp__telegram__telegram-webhook-register, mcp__whatsapp__whatsapp-login-start, mcp__whatsapp__whatsapp-login-wait, mcp__whatsapp__whatsapp-status, mcp__whatsapp__whatsapp-disconnect, mcp__whatsapp__whatsapp-send, mcp__whatsapp__whatsapp-send-document, mcp__whatsapp__whatsapp-config, mcp__whatsapp__whatsapp-activity, mcp__whatsapp__whatsapp-conversations, mcp__whatsapp__whatsapp-messages, mcp__whatsapp__whatsapp-conversation-graph-state, mcp__whatsapp__whatsapp-group-info, mcp__email__email-setup, mcp__email__email-read, mcp__email__email-send, mcp__email__email-reply, mcp__email__email-search, mcp__email__email-graph-query, mcp__email__email-otp-extract, mcp__email__email-status, mcp__email__email-fetch, mcp__email__email-ingest, mcp__outlook__outlook-account-register, mcp__outlook__outlook-mail-list, mcp__outlook__outlook-mail-search, mcp__outlook__outlook-calendar-list, mcp__outlook__outlook-calendar-event, mcp__outlook__outlook-contacts-list, mcp__outlook__outlook-mailbox-info, mcp__scheduling__schedule-event, mcp__scheduling__schedule-list, mcp__scheduling__schedule-get, mcp__scheduling__schedule-update, mcp__scheduling__schedule-cancel, mcp__scheduling__schedule-export-ics, mcp__scheduling__schedule-import-ics, mcp__scheduling__time-resolve, mcp__memory__memory-search, mcp__memory__profile-update, mcp__plugin_playwright_playwright__browser_navigate, mcp__plugin_playwright_playwright__browser_navigate_back, mcp__plugin_playwright_playwright__browser_snapshot, mcp__plugin_playwright_playwright__browser_click, mcp__plugin_playwright_playwright__browser_fill, mcp__plugin_playwright_playwright__browser_fill_form, mcp__plugin_playwright_playwright__browser_type, mcp__plugin_playwright_playwright__browser_press_key, mcp__plugin_playwright_playwright__browser_hover, mcp__plugin_playwright_playwright__browser_select_option, mcp__plugin_playwright_playwright__browser_wait_for, mcp__plugin_playwright_playwright__browser_handle_dialog, mcp__plugin_playwright_playwright__browser_evaluate, mcp__plugin_playwright_playwright__browser_console_messages, mcp__plugin_playwright_playwright__browser_resize, mcp__plugin_playwright_playwright__browser_tabs, mcp__plugin_playwright_playwright__browser_close
|
|
6
|
+
tools: Skill, mcp__admin__system-status, mcp__admin__brand-settings, mcp__admin__account-manage, mcp__admin__account-update, mcp__admin__logs-read, mcp__admin__plugin-read, mcp__admin__file-attach, mcp__admin__wifi, mcp__contacts__contact-create, mcp__contacts__contact-lookup, mcp__contacts__contact-update, mcp__contacts__contact-delete, mcp__contacts__contact-list, mcp__contacts__contact-export, mcp__contacts__contact-erase, mcp__contacts__group-create, mcp__contacts__group-manage, mcp__telegram__message, mcp__telegram__message-history, mcp__telegram__telegram-webhook-register, mcp__whatsapp__whatsapp-login-start, mcp__whatsapp__whatsapp-login-wait, mcp__whatsapp__whatsapp-status, mcp__whatsapp__whatsapp-disconnect, mcp__whatsapp__whatsapp-send, mcp__whatsapp__whatsapp-send-document, mcp__whatsapp__whatsapp-config, mcp__whatsapp__whatsapp-activity, mcp__whatsapp__whatsapp-conversations, mcp__whatsapp__whatsapp-messages, mcp__whatsapp__whatsapp-conversation-graph-state, mcp__whatsapp__whatsapp-group-info, mcp__email__email-setup, mcp__email__email-read, mcp__email__email-send, mcp__email__email-reply, mcp__email__email-search, mcp__email__email-graph-query, mcp__email__email-otp-extract, mcp__email__email-status, mcp__email__email-fetch, mcp__email__email-ingest, mcp__outlook__outlook-account-register, mcp__outlook__outlook-mail-list, mcp__outlook__outlook-mail-search, mcp__outlook__outlook-calendar-list, mcp__outlook__outlook-calendar-event, mcp__outlook__outlook-contacts-list, mcp__outlook__outlook-mailbox-info, mcp__scheduling__schedule-event, mcp__scheduling__schedule-list, mcp__scheduling__schedule-get, mcp__scheduling__schedule-update, mcp__scheduling__schedule-cancel, mcp__scheduling__schedule-export-ics, mcp__scheduling__schedule-import-ics, mcp__scheduling__time-resolve, mcp__memory__memory-search, mcp__memory__profile-update, mcp__plugin_playwright_playwright__browser_navigate, mcp__plugin_playwright_playwright__browser_navigate_back, mcp__plugin_playwright_playwright__browser_snapshot, mcp__plugin_playwright_playwright__browser_click, mcp__plugin_playwright_playwright__browser_fill, mcp__plugin_playwright_playwright__browser_fill_form, mcp__plugin_playwright_playwright__browser_type, mcp__plugin_playwright_playwright__browser_press_key, mcp__plugin_playwright_playwright__browser_hover, mcp__plugin_playwright_playwright__browser_select_option, mcp__plugin_playwright_playwright__browser_wait_for, mcp__plugin_playwright_playwright__browser_handle_dialog, mcp__plugin_playwright_playwright__browser_evaluate, mcp__plugin_playwright_playwright__browser_console_messages, mcp__plugin_playwright_playwright__browser_resize, mcp__plugin_playwright_playwright__browser_tabs, mcp__plugin_playwright_playwright__browser_close
|
|
7
7
|
---
|
|
8
8
|
|
|
9
9
|
# Personal Assistant
|
|
@@ -22,8 +22,8 @@ These three rules win when anything else in this prompt conflicts with them.
|
|
|
22
22
|
|
|
23
23
|
Each domain has a small set of tools and, where it exists, a skill that drives the multi-step flow. Match the brief to the domain, load the skill if one is named, and run the tools the skill prescribes.
|
|
24
24
|
|
|
25
|
-
- **WhatsApp setup or config:**
|
|
26
|
-
- **Cloudflare tunnel:**
|
|
25
|
+
- **WhatsApp setup or config:** **After routing, the first tool call MUST be `Skill connect-whatsapp` (for QR pairing and admin-phone setup) or `Skill manage-whatsapp-config` (for DM/group policies). Any channel tool call before the routed skill's content is loaded into context is a contract violation.** Load `skill-load skillName=connect-whatsapp` for QR pairing and admin-phone setup; load `skill-load skillName=manage-whatsapp-config` for DM/group policies and admin-phone management. The skills carry the per-phase flow.
|
|
26
|
+
- **Cloudflare tunnel:** **After routing, the first tool call MUST be `Skill setup-tunnel`. Any Bash call before the skill content is loaded into context is a contract violation.** Load `skill-load skillName=setup-tunnel`. The skill drives `cloudflared` directly via Bash following `references/manual-setup.md`, `references/reset-guide.md`, and `references/dashboard-guide.md`. There is no shell-script wrapper; PTY stdout is the only surface.
|
|
27
27
|
- **Every other domain** (scheduling, Telegram, email, Outlook, contacts, browser, platform admin) runs through the tool descriptions injected into your system prompt. The rules below apply across these domains regardless of which tool is invoked.
|
|
28
28
|
|
|
29
29
|
## Cross-domain rules
|
|
@@ -56,4 +56,4 @@ Name the tool, what you tried, and what the `[tool-failure-diag]` line shows. Do
|
|
|
56
56
|
|
|
57
57
|
## Plain English
|
|
58
58
|
|
|
59
|
-
Load `skill-load skillName=plainly` on the first turn and apply it to every prose payload returned to admin and to every message body destined for a human reader (email bodies, WhatsApp text, status summaries). It does not apply to structured tool arguments (cron expressions, scheduling enums, browser selectors).
|
|
59
|
+
**The first tool call MUST be `Skill plainly`. Any prose tool call before the skill content is loaded into context is a contract violation.** Load `skill-load skillName=plainly` on the first turn and apply it to every prose payload returned to admin and to every message body destined for a human reader (email bodies, WhatsApp text, status summaries). It does not apply to structured tool arguments (cron expressions, scheduling enums, browser selectors).
|
|
@@ -3,7 +3,7 @@ name: project-manager
|
|
|
3
3
|
description: "Project and task management. Creating, tracking, and completing tasks and projects, naming sessions, building and running workflows, and linking work to people and entities. Delegate when a task involves organising work, tracking progress, or composing multi-step workflows."
|
|
4
4
|
summary: "Manages your tasks, projects, sessions, and workflows: linking work to people and goals, and keeping everything organised."
|
|
5
5
|
model: claude-sonnet-4-6
|
|
6
|
-
tools: mcp__work__work-create, mcp__work__work-update, mcp__work__work-list, mcp__work__work-get, mcp__work__work-relate, mcp__work__work-complete, mcp__work__work-ready, mcp__work__project-create, mcp__work__project-list, mcp__work__project-get, mcp__work__project-update, mcp__work__project-complete, mcp__work__session-list, mcp__work__session-name, mcp__workflows__workflow-create, mcp__workflows__workflow-list, mcp__workflows__workflow-get, mcp__workflows__workflow-update, mcp__workflows__workflow-delete, mcp__workflows__workflow-validate, mcp__workflows__workflow-execute, mcp__workflows__workflow-runs, mcp__memory__memory-search
|
|
6
|
+
tools: mcp__work__work-create, mcp__work__work-update, mcp__work__work-list, mcp__work__work-get, mcp__work__work-relate, mcp__work__work-complete, mcp__work__work-ready, mcp__work__project-create, mcp__work__project-list, mcp__work__project-get, mcp__work__project-update, mcp__work__project-complete, mcp__work__session-list, mcp__work__session-name, mcp__workflows__workflow-create, mcp__workflows__workflow-list, mcp__workflows__workflow-get, mcp__workflows__workflow-update, mcp__workflows__workflow-delete, mcp__workflows__workflow-validate, mcp__workflows__workflow-execute, mcp__workflows__workflow-runs, mcp__memory__memory-search, Skill
|
|
7
7
|
---
|
|
8
8
|
|
|
9
9
|
# Project Manager
|
|
@@ -60,4 +60,4 @@ Name the tool, what you tried, and what the `[tool-failure-diag]` line shows. Do
|
|
|
60
60
|
|
|
61
61
|
## Plain English
|
|
62
62
|
|
|
63
|
-
Load `skill-load skillName=plainly` on the first turn and apply it to every prose payload returned to admin (status updates, sprint summaries, project digests) and to task title/description fields a human will read. It does not apply to structured arguments (state enums, IDs, JSON-shaped relationship payloads).
|
|
63
|
+
**The first tool call MUST be `Skill plainly`. Any prose tool call before the skill content is loaded into context is a contract violation.** Load `skill-load skillName=plainly` on the first turn and apply it to every prose payload returned to admin (status updates, sprint summaries, project digests) and to task title/description fields a human will read. It does not apply to structured arguments (state enums, IDs, JSON-shaped relationship payloads).
|
|
@@ -3,7 +3,7 @@ name: research-assistant
|
|
|
3
3
|
description: "Deep research, information gathering, knowledge management, and supporting visuals. Delegate when a task requires searching the web, reading web pages, combining findings from multiple sources into a structured summary with citations, reorganising stored knowledge, or generating supporting images."
|
|
4
4
|
summary: "Researches topics online, manages your knowledge graph, and produces supporting visuals."
|
|
5
5
|
model: claude-opus-4-7
|
|
6
|
-
tools: WebSearch, WebFetch, mcp__memory__memory-search, mcp__memory__memory-write, mcp__memory__memory-reindex, mcp__replicate__image-generate, mcp__plugin_playwright_playwright__browser_navigate, mcp__plugin_playwright_playwright__browser_snapshot, mcp__plugin_playwright_playwright__browser_evaluate
|
|
6
|
+
tools: WebSearch, WebFetch, Skill, mcp__memory__memory-search, mcp__memory__memory-write, mcp__memory__memory-reindex, mcp__replicate__image-generate, mcp__plugin_playwright_playwright__browser_navigate, mcp__plugin_playwright_playwright__browser_snapshot, mcp__plugin_playwright_playwright__browser_evaluate
|
|
7
7
|
---
|
|
8
8
|
|
|
9
9
|
# Research Assistant
|
|
@@ -70,4 +70,4 @@ Name the tool, the target URL, and the `[tool-failure-diag]` block if present. S
|
|
|
70
70
|
|
|
71
71
|
## Plain English
|
|
72
72
|
|
|
73
|
-
Load `skill-load skillName=plainly` on the first turn and apply it to every prose payload returned to admin (research summaries, the "Key findings" section). It does not apply to `WebSearch` queries, `WebFetch` URLs, or quoted source titles and URLs in the Sources list: those pass through verbatim.
|
|
73
|
+
**The first tool call MUST be `Skill plainly`. Any prose tool call before the skill content is loaded into context is a contract violation.** Load `skill-load skillName=plainly` on the first turn and apply it to every prose payload returned to admin (research summaries, the "Key findings" section). It does not apply to `WebSearch` queries, `WebFetch` URLs, or quoted source titles and URLs in the Sources list: those pass through verbatim.
|
|
@@ -16,6 +16,9 @@ tools:
|
|
|
16
16
|
- name: voice-record-feedback
|
|
17
17
|
publicAllowlist: false
|
|
18
18
|
adminAllowlist: true
|
|
19
|
+
- name: voice-ingest-session-text
|
|
20
|
+
publicAllowlist: false
|
|
21
|
+
adminAllowlist: true
|
|
19
22
|
always: false
|
|
20
23
|
embed: false
|
|
21
24
|
mcp:
|
|
@@ -87,7 +90,7 @@ The user is:
|
|
|
87
90
|
|
|
88
91
|
| Skill | Purpose |
|
|
89
92
|
|-------|---------|
|
|
90
|
-
| `voice-mirror` | Capture the operator's voice from their own writing (`human-only` corpus) and condition agent drafts on it.
|
|
93
|
+
| `voice-mirror` | Capture the operator's voice from their own writing (`human-only` corpus) and condition agent drafts on it. Five tools: tag historical content (with auto-derived format), distil a per-format style card, retrieve conditioning for a drafting brief (requires `brief.format`), record operator edits as feedback, and auto-ingest PTY turns at SessionEnd. Other drafting skills (email composition, Postiz, property-brochure, prospectus) call it transparently — opt-out via `voiceMirror: false` in the calling skill's frontmatter. |
|
|
91
94
|
|
|
92
95
|
## Specialist Agent
|
|
93
96
|
|
|
@@ -99,14 +102,15 @@ The manuscript-reviewer agent operates in its own context window with file tools
|
|
|
99
102
|
|
|
100
103
|
## Tools
|
|
101
104
|
|
|
102
|
-
Voice-mirror introduces
|
|
105
|
+
Voice-mirror introduces five deterministic plugin tools. They route writes through `memory-write` so the graph-write gate stamps provenance on every node.
|
|
103
106
|
|
|
104
107
|
| Tool | Purpose |
|
|
105
108
|
|------|---------|
|
|
106
|
-
| `voice-tag-content` | Stamp `authorshipMode ∈ {human-only, human-led-agent-assisted, agent-led-human-reviewed, agent-only, unknown}` on one or many `:KnowledgeDocument | :Message | :SocialPost` nodes (email threads live as `:KnowledgeDocument {source:'email'}` since Task 321). Bulk-mode for backfill batches. |
|
|
107
|
-
| `voice-distil-profile` | Walk the operator's `human-only` corpus and persist a `:VoiceProfile {styleCard, generatedAt, corpusSize, feedbackEntries}` linked to the `:AdminUser`. Cadence-guarded: re-runs on ≥20% corpus growth or ≥30 days, otherwise no-op. |
|
|
108
|
-
| `voice-retrieve-conditioning` | Return `{styleCard, exemplars[]}` for a drafting brief. K=5 short-form, K=15 long-form. Token-budget bounded. Graceful degradation: empty profile → `{styleCard: null, exemplars: []}`. |
|
|
109
|
-
| `voice-record-feedback` | Capture an operator edit on an agent draft as a `:VoiceEdit` with a Haiku-summarised `intent`, linked back to the operator's `:VoiceProfile` via `:FEEDBACK_FOR`. |
|
|
109
|
+
| `voice-tag-content` | Stamp `authorshipMode ∈ {human-only, human-led-agent-assisted, agent-led-human-reviewed, agent-only, unknown}` and derived `format ∈ {text, email, social-post, article, note, marketing-copy}` on one or many `:KnowledgeDocument | :Message | :SocialPost` nodes (email threads live as `:KnowledgeDocument {source:'email'}` since Task 321). Bulk-mode for backfill batches. Pass `format` explicitly to override auto-derivation. |
|
|
110
|
+
| `voice-distil-profile` | Walk the operator's `human-only` corpus for the given `format` and persist a `:VoiceProfile {styleCard, generatedAt, corpusSize, feedbackEntries, format}` linked to the `:AdminUser`. Omit `format` to enumerate all formats in the corpus and distil each. Cadence-guarded per format: re-runs on ≥20% corpus growth or ≥30 days, otherwise no-op. |
|
|
111
|
+
| `voice-retrieve-conditioning` | Return `{styleCard, exemplars[]}` for a drafting brief. Requires `brief.format` (one of the six corpus formats). K=5 short-form (`brief.length:'short'`), K=15 long-form (`brief.length:'long'`). Token-budget bounded. Graceful degradation: empty profile → `{styleCard: null, exemplars: []}`. |
|
|
112
|
+
| `voice-record-feedback` | Capture an operator edit on an agent draft as a `:VoiceEdit {format}` with a Haiku-summarised `intent`, linked back to the operator's per-format `:VoiceProfile` via `:FEEDBACK_FOR`. Requires `format`. |
|
|
113
|
+
| `voice-ingest-session-text` | Ingest operator PTY turns from a JSONL transcript as `:Message {format:'text', authorshipMode:'human-only'}` corpus nodes. Deduplicates via SHA256 `contentHash`. Called by `voice-session-end-text.sh` at SessionEnd; not intended for direct agent invocation. |
|
|
110
114
|
|
|
111
115
|
The non-voice skills continue to operate via existing platform tools (`memory-search` for knowledge retrieval). Structured choices are still presented as numbered lists in plain chat — the platform has no inline-UI component primitive on the admin / native-CC surface.
|
|
112
116
|
|
|
@@ -127,4 +131,4 @@ Domain knowledge files loaded on demand by each skill. See individual skill file
|
|
|
127
131
|
| `review-manuscript` | `review-manuscript-checklist.md` |
|
|
128
132
|
| `review-scene` | `scene-analysis-framework.md` |
|
|
129
133
|
| `review-prose` | `prose-review-checklist.md` |
|
|
130
|
-
| `voice-mirror` | No external references; the skill body defines the
|
|
134
|
+
| `voice-mirror` | No external references; the skill body defines the five tool contracts. Developer notes in `maxy-code/.docs/voice-mirror.md`. |
|