@rubytech/create-maxy 1.0.421 → 1.0.423

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rubytech/create-maxy",
3
- "version": "1.0.421",
3
+ "version": "1.0.423",
4
4
  "description": "Install Maxy — AI for Productive People",
5
5
  "bin": {
6
6
  "create-maxy": "./dist/index.js"
@@ -3822,7 +3822,7 @@ async function loadSessionContext(accountId) {
3822
3822
  try {
3823
3823
  const summaryResult = await session.run(
3824
3824
  `MATCH (n:CreativeWork {accountId: $accountId})
3825
- WHERE n.title STARTS WITH 'Session Summary'
3825
+ WHERE n.title STARTS WITH 'Session Summary' OR n.title = 'Session Snapshot'
3826
3826
  RETURN n.title AS title, n.createdAt AS createdAt, n.abstract AS abstract
3827
3827
  ORDER BY n.createdAt DESC LIMIT 1`,
3828
3828
  { accountId }
@@ -3852,14 +3852,24 @@ async function loadSessionContext(accountId) {
3852
3852
  { accountId, limit: neo4j.int(MAX_SESSION_TASKS) }
3853
3853
  );
3854
3854
  const sections = [];
3855
+ const STALENESS_LIMIT_MS = 48 * 60 * 60 * 1e3;
3855
3856
  if (summaryResult.records.length > 0) {
3856
3857
  const rec = summaryResult.records[0];
3857
3858
  const title = rec.get("title");
3858
3859
  const createdAt = rec.get("createdAt");
3859
3860
  const abstract = rec.get("abstract");
3860
- const dateSuffix = createdAt ? ` (${createdAt.slice(0, 10)})` : "";
3861
- sections.push(`## Last Session${dateSuffix}
3861
+ let isStale = false;
3862
+ if (createdAt) {
3863
+ const ageMs = Date.now() - new Date(createdAt).getTime();
3864
+ isStale = !isNaN(ageMs) && ageMs > STALENESS_LIMIT_MS;
3865
+ }
3866
+ if (isStale) {
3867
+ console.error(`[session-context] Skipped stale summary for ${accountId.slice(0, 8)}\u2026: title="${title}" createdAt=${createdAt}`);
3868
+ } else {
3869
+ const dateSuffix = createdAt ? ` (${createdAt.slice(0, 10)})` : "";
3870
+ sections.push(`## Last Session${dateSuffix}
3862
3871
  ${abstract}`);
3872
+ }
3863
3873
  }
3864
3874
  if (digestResult.records.length > 0) {
3865
3875
  const rec = digestResult.records[0];
@@ -3885,8 +3895,9 @@ ${abstract}`);
3885
3895
  ${taskLines.join("\n")}`);
3886
3896
  }
3887
3897
  if (sections.length === 0) return null;
3898
+ const summaryCreatedAt = summaryResult.records.length > 0 ? summaryResult.records[0].get("createdAt") ?? "unknown" : "n/a";
3888
3899
  console.error(
3889
- `[session-context] Loaded for ${accountId.slice(0, 8)}\u2026: summary=${summaryResult.records.length > 0 ? "yes" : "no"}, digest=${digestResult.records.length > 0 ? "yes" : "no"}, tasks=${tasksResult.records.length}`
3900
+ `[session-context] Loaded for ${accountId.slice(0, 8)}\u2026: summary=${summaryResult.records.length > 0 ? "yes" : "no"}, summaryDate=${summaryCreatedAt}, digest=${digestResult.records.length > 0 ? "yes" : "no"}, tasks=${tasksResult.records.length}`
3890
3901
  );
3891
3902
  return `<previous-context>
3892
3903
  ${sections.join("\n\n")}
@@ -3898,6 +3909,22 @@ ${sections.join("\n\n")}
3898
3909
  await session.close();
3899
3910
  }
3900
3911
  }
3912
+ async function writeSessionSummary(accountId, summary) {
3913
+ const session = getSession();
3914
+ try {
3915
+ const createdAt = (/* @__PURE__ */ new Date()).toISOString();
3916
+ await session.run(
3917
+ `MERGE (n:CreativeWork {accountId: $accountId, title: 'Session Snapshot'})
3918
+ SET n.abstract = $summary, n.createdAt = $createdAt, n.scope = 'admin'`,
3919
+ { accountId, summary, createdAt }
3920
+ );
3921
+ console.error(`[session-summary] Written for ${accountId.slice(0, 8)}\u2026`);
3922
+ } catch (err) {
3923
+ console.error(`[session-summary] Failed for ${accountId.slice(0, 8)}\u2026: ${err instanceof Error ? err.message : String(err)}`);
3924
+ } finally {
3925
+ await session.close();
3926
+ }
3927
+ }
3901
3928
  async function loadOnboardingStep(accountId) {
3902
3929
  const session = getSession();
3903
3930
  try {
@@ -4777,7 +4804,16 @@ function validateSession(sessionKey, agentType) {
4777
4804
  if (!session) return false;
4778
4805
  if (session.agentType !== agentType) return false;
4779
4806
  if (Date.now() - session.createdAt > 24 * 60 * 60 * 1e3) {
4807
+ const history = session.messageHistory;
4808
+ const expiredAccountId = session.accountId;
4780
4809
  sessionStore.delete(sessionKey);
4810
+ if (history && history.length >= 2) {
4811
+ writeEndOfTurnSummary(expiredAccountId, history).catch(
4812
+ (err) => console.error(`[session-summary] expiry write failed: ${err instanceof Error ? err.message : String(err)}`)
4813
+ );
4814
+ } else {
4815
+ console.error(`[session-summary] Session ${sessionKey.slice(0, 8)}\u2026 expired without summary \u2014 ${history?.length ?? 0} messages`);
4816
+ }
4781
4817
  return false;
4782
4818
  }
4783
4819
  if (session.grantExpiresAt && Date.now() > session.grantExpiresAt) {
@@ -5061,6 +5097,80 @@ function getAdminAllowedTools(enabledPlugins) {
5061
5097
  }
5062
5098
  return tools;
5063
5099
  }
5100
+ var QUERY_CLASSIFIER_MODEL = "claude-haiku-4-5-20251001";
5101
+ var QUERY_CLASSIFIER_TIMEOUT_MS = 3e3;
5102
+ var QUERY_CLASSIFIER_MSG_CAP = 500;
5103
+ var QUERY_CLASSIFIER_HISTORY_TURNS = 4;
5104
+ var QUERY_CLASSIFIER_FALLBACK = {
5105
+ search: true,
5106
+ query: null,
5107
+ // null means "use raw message"
5108
+ reason: "classifier-fallback"
5109
+ };
5110
+ var QUERY_CLASSIFIER_SYSTEM = `You decide whether a user message to a business assistant requires a knowledge base search.
5111
+
5112
+ The knowledge base contains the business's products, services, pricing, policies, and domain expertise. It does NOT contain conversation history \u2014 the assistant already has that.
5113
+
5114
+ Respond with ONLY a JSON object: {"search": boolean, "query": string | null, "reason": string}
5115
+
5116
+ Set search to false when:
5117
+ - The message is a greeting, farewell, acknowledgement, or filler ("hello", "thanks", "ok", "bye")
5118
+ - The message is about session state ("continue where we left off", "what were we discussing")
5119
+ - The conversation history already contains sufficient information to answer the question
5120
+ - The message is a conversational response that doesn't require new factual knowledge
5121
+
5122
+ Set search to true when:
5123
+ - The message asks about products, services, pricing, capabilities, or business information
5124
+ - The message introduces a new topic not already covered in the conversation
5125
+ - The message requires factual knowledge the assistant wouldn't have from conversation alone
5126
+
5127
+ When search is true, set query to a search-optimised phrase that captures the information need. Resolve references from conversation history \u2014 e.g. if the user says "tell me more about the first one" and the history mentions "property valuations", set query to "property valuations details". If the raw message is already a good search query, use it as-is.
5128
+
5129
+ When search is false, set query to null and reason to a brief category (e.g. "greeting", "acknowledgement", "session-reference", "context-sufficient").`;
5130
+ async function classifyMemoryQuery(message, history) {
5131
+ let apiKey = process.env.ANTHROPIC_API_KEY;
5132
+ if (!apiKey) {
5133
+ try {
5134
+ apiKey = readFileSync5(API_KEY_FILE, "utf-8").trim();
5135
+ } catch {
5136
+ }
5137
+ }
5138
+ if (!apiKey) return QUERY_CLASSIFIER_FALLBACK;
5139
+ const recentHistory = history.slice(-QUERY_CLASSIFIER_HISTORY_TURNS);
5140
+ const transcript = recentHistory.length > 0 ? recentHistory.map((m) => `[${m.role}] ${m.content.slice(0, QUERY_CLASSIFIER_MSG_CAP)}`).join("\n") : "(no conversation history \u2014 this is the first message)";
5141
+ const userContent = [
5142
+ `Conversation history:
5143
+ ${transcript}`,
5144
+ `
5145
+ Current message:
5146
+ ${message.slice(0, QUERY_CLASSIFIER_MSG_CAP)}`
5147
+ ].join("\n");
5148
+ const controller = new AbortController();
5149
+ const timer = setTimeout(() => controller.abort(), QUERY_CLASSIFIER_TIMEOUT_MS);
5150
+ try {
5151
+ const client = new Anthropic({ apiKey });
5152
+ const response = await client.messages.create({
5153
+ model: QUERY_CLASSIFIER_MODEL,
5154
+ max_tokens: 150,
5155
+ system: QUERY_CLASSIFIER_SYSTEM,
5156
+ messages: [{ role: "user", content: userContent }]
5157
+ }, { signal: controller.signal });
5158
+ const text = response.content.filter((b) => b.type === "text").map((b) => "text" in b ? b.text : "").join("").trim();
5159
+ if (!text) return QUERY_CLASSIFIER_FALLBACK;
5160
+ const jsonStr = text.replace(/^```json\s*/i, "").replace(/```\s*$/, "").trim();
5161
+ const parsed = JSON.parse(jsonStr);
5162
+ if (typeof parsed.search !== "boolean") return QUERY_CLASSIFIER_FALLBACK;
5163
+ return {
5164
+ search: parsed.search,
5165
+ query: parsed.search && typeof parsed.query === "string" ? parsed.query.slice(0, QUERY_CLASSIFIER_MSG_CAP) : null,
5166
+ reason: typeof parsed.reason === "string" ? parsed.reason.replace(/[\n\r]/g, " ").slice(0, 100) : "unknown"
5167
+ };
5168
+ } catch {
5169
+ return QUERY_CLASSIFIER_FALLBACK;
5170
+ } finally {
5171
+ clearTimeout(timer);
5172
+ }
5173
+ }
5064
5174
  async function fetchMemoryContext(accountId, query, sessionKey, options) {
5065
5175
  const serverPath = resolve4(PLATFORM_ROOT3, "plugins/memory/mcp/dist/index.js");
5066
5176
  if (!existsSync5(serverPath)) {
@@ -5456,6 +5566,65 @@ Extract preference updates as JSON array.`
5456
5566
  clearTimeout(timer);
5457
5567
  }
5458
5568
  }
5569
+ var SESSION_SUMMARY_PROMPT = `You are summarising a conversation between a business assistant and its owner. Write a 3-5 sentence summary covering:
5570
+ - What was discussed and accomplished this session
5571
+ - Any tasks created, decisions made, or state changes
5572
+ - Current state of any ongoing work
5573
+ - What the owner is likely to want to continue next
5574
+
5575
+ Be factual and specific. Use present tense for current state. Do not include greetings or meta-commentary.`;
5576
+ var SESSION_SUMMARY_TIMEOUT_MS = 1e4;
5577
+ var lastSummaryWrite = /* @__PURE__ */ new Map();
5578
+ var SUMMARY_RATE_LIMIT_MS = 5 * 60 * 1e3;
5579
+ async function generateSessionSummary(history) {
5580
+ if (history.length < 2) return null;
5581
+ let apiKey = process.env.ANTHROPIC_API_KEY;
5582
+ if (!apiKey) {
5583
+ try {
5584
+ apiKey = readFileSync5(API_KEY_FILE, "utf-8").trim();
5585
+ } catch {
5586
+ return null;
5587
+ }
5588
+ }
5589
+ if (!apiKey) {
5590
+ console.error("[session-summary] Skipping \u2014 no API key available");
5591
+ return null;
5592
+ }
5593
+ const transcript = history.slice(-20).map((m) => `[${m.role}] ${m.content}`).join("\n\n");
5594
+ const controller = new AbortController();
5595
+ const timer = setTimeout(() => controller.abort(), SESSION_SUMMARY_TIMEOUT_MS);
5596
+ try {
5597
+ const client = new Anthropic({ apiKey });
5598
+ const response = await client.messages.create({
5599
+ model: REFLECTION_MODEL,
5600
+ max_tokens: 500,
5601
+ system: SESSION_SUMMARY_PROMPT,
5602
+ messages: [{ role: "user", content: `Conversation:
5603
+ ${transcript}` }]
5604
+ }, { signal: controller.signal });
5605
+ return response.content.filter((b) => b.type === "text").map((b) => "text" in b ? b.text : "").join("");
5606
+ } catch (err) {
5607
+ if (err instanceof Error && err.name === "AbortError") {
5608
+ console.error(`[session-summary] Haiku call timed out after ${SESSION_SUMMARY_TIMEOUT_MS}ms`);
5609
+ } else {
5610
+ console.error(`[session-summary] Haiku call failed: ${err instanceof Error ? err.message : String(err)}`);
5611
+ }
5612
+ return null;
5613
+ } finally {
5614
+ clearTimeout(timer);
5615
+ }
5616
+ }
5617
+ async function writeEndOfTurnSummary(accountId, history) {
5618
+ const now = Date.now();
5619
+ const lastWrite = lastSummaryWrite.get(accountId) ?? 0;
5620
+ if (now - lastWrite < SUMMARY_RATE_LIMIT_MS) {
5621
+ return;
5622
+ }
5623
+ const summary = await generateSessionSummary(history);
5624
+ if (!summary) return;
5625
+ await writeSessionSummary(accountId, summary);
5626
+ lastSummaryWrite.set(accountId, Date.now());
5627
+ }
5459
5628
  var MANAGED_WORK_BUDGET_RATIO = 0.5;
5460
5629
  var TOOL_SCHEMA_OVERHEAD_TOKENS = 15e3;
5461
5630
  function estimateTokens(text) {
@@ -6503,6 +6672,9 @@ async function* invokeManagedAdminAgent(message, systemPrompt, accountDir, accou
6503
6672
  if (responseText) persistMessage(convId, "assistant", responseText, accountId, capturedTokens, assistantTimestamp).catch(() => {
6504
6673
  });
6505
6674
  }
6675
+ writeEndOfTurnSummary(accountId, afterHistory).catch(
6676
+ (err) => console.error(`[session-summary] end-of-turn write failed: ${err instanceof Error ? err.message : String(err)}`)
6677
+ );
6506
6678
  }
6507
6679
  yield event;
6508
6680
  }
@@ -6581,18 +6753,32 @@ async function* invokePublicAgent(message, systemPrompt, accountId, accountDir,
6581
6753
  }
6582
6754
  }
6583
6755
  }
6756
+ const history = sessionKey ? getMessageHistory(sessionKey) : [];
6584
6757
  const fetchOptions = {
6585
6758
  ...agentSlug ? { agentSlug } : {},
6586
6759
  ...knowledgeKeywords && knowledgeKeywords.length > 0 ? { knowledgeKeywords } : {}
6587
6760
  };
6761
+ const needsClassification = !(knowledgeBaked && !liveMemory);
6762
+ const classifyStartMs = Date.now();
6763
+ const classification = needsClassification ? await classifyMemoryQuery(message, history) : QUERY_CLASSIFIER_FALLBACK;
6764
+ const classifyMs = Date.now() - classifyStartMs;
6765
+ const effectiveQuery = classification.query ?? message;
6766
+ if (needsClassification) {
6767
+ streamLog.write(`[${isoTs()}] [public-query-classifier] search=${classification.search} effectiveQuery=${JSON.stringify(effectiveQuery.slice(0, 200))} reason=${classification.reason} latencyMs=${classifyMs}
6768
+ `);
6769
+ }
6588
6770
  let system;
6589
6771
  if (knowledgeBaked && !liveMemory) {
6590
6772
  streamLog.write(`[${isoTs()}] [public-knowledge-source] baked \u2014 skipping memory-search (liveMemory=false)
6773
+ `);
6774
+ system = systemPrompt;
6775
+ } else if (!classification.search) {
6776
+ streamLog.write(`[${isoTs()}] [public-knowledge-source] skipped \u2014 classifier (reason=${classification.reason})
6591
6777
  `);
6592
6778
  system = systemPrompt;
6593
6779
  } else if (knowledgeBaked && liveMemory) {
6594
- const memoryContext = await fetchMemoryContext(accountId, message, sessionKey, fetchOptions);
6595
- streamLog.write(`[${isoTs()}] [public-knowledge-source] baked+live agentSlug=${agentSlug ?? "none"} keywords=${knowledgeKeywords?.length ?? 0} result=${memoryContext ? `ok (${memoryContext.length} chars)` : "null"}
6780
+ const memoryContext = await fetchMemoryContext(accountId, effectiveQuery, sessionKey, fetchOptions);
6781
+ streamLog.write(`[${isoTs()}] [public-knowledge-source] baked+live agentSlug=${agentSlug ?? "none"} keywords=${knowledgeKeywords?.length ?? 0} effectiveQuery=${JSON.stringify(effectiveQuery.slice(0, 200))} result=${memoryContext ? `ok (${memoryContext.length} chars)` : "null"}
6596
6782
  `);
6597
6783
  system = memoryContext ? `${systemPrompt}
6598
6784
 
@@ -6600,8 +6786,8 @@ async function* invokePublicAgent(message, systemPrompt, accountId, accountDir,
6600
6786
  ${memoryContext}
6601
6787
  </live-memory>` : systemPrompt;
6602
6788
  } else {
6603
- const memoryContext = await fetchMemoryContext(accountId, message, sessionKey, fetchOptions);
6604
- streamLog.write(`[${isoTs()}] [public-knowledge-source] memory-search agentSlug=${agentSlug ?? "none"} keywords=${knowledgeKeywords?.length ?? 0} result=${memoryContext ? `ok (${memoryContext.length} chars)` : "null \u2014 agent has no knowledge"}
6789
+ const memoryContext = await fetchMemoryContext(accountId, effectiveQuery, sessionKey, fetchOptions);
6790
+ streamLog.write(`[${isoTs()}] [public-knowledge-source] memory-search agentSlug=${agentSlug ?? "none"} keywords=${knowledgeKeywords?.length ?? 0} effectiveQuery=${JSON.stringify(effectiveQuery.slice(0, 200))} result=${memoryContext ? `ok (${memoryContext.length} chars)` : "null \u2014 agent has no knowledge"}
6605
6791
  `);
6606
6792
  if (memoryContext) {
6607
6793
  streamLog.write(`[${isoTs()}] [public-memory-context] ${JSON.stringify(memoryContext.slice(0, 500))}${memoryContext.length > 500 ? "\u2026" : ""}
@@ -6613,7 +6799,6 @@ ${memoryContext}
6613
6799
  ${memoryContext}
6614
6800
  </memory>` : systemPrompt;
6615
6801
  }
6616
- const history = sessionKey ? getMessageHistory(sessionKey) : [];
6617
6802
  const sdkMessages = [
6618
6803
  ...history.map((m) => ({ role: m.role, content: m.content })),
6619
6804
  { role: "user", content: message }
@@ -87,9 +87,14 @@ For the most recent session: call `session-list` with `limit: 1`, then call `ses
87
87
 
88
88
  ## Session Memory
89
89
 
90
- The platform automatically injects recalled context into your system prompt as a `<previous-context>` section. This includes the most recent session summary and all open/active tasks. Treat this as background context it informs your awareness but does not override the current conversation.
90
+ The platform automatically injects recalled context into your system prompt as a `<previous-context>` section. This includes the most recent session summary and all open/active tasks. The platform rejects stale summaries (older than 48 hours) when present, the summary is recent and trustworthy.
91
91
 
92
- When `<previous-context>` is present, use it to orient yourself and greet the owner with awareness of prior work and outstanding tasks. When absent, Neo4j was unreachable or no prior context exists — proceed normally.
92
+ When `<previous-context>` is present:
93
+ - **Trust the session summary for state orientation.** It reflects the end of the most recent session. Do not re-verify claims already described — if the summary says onboarding is complete, do not call `onboarding-get`. If it names tasks in progress, acknowledge and resume them.
94
+ - **Do not re-research context captured in the summary.** When the summary describes work in progress, outstanding tasks, or recent decisions, pick up from that state. Redundant memory-search or tool calls for information already in the summary waste the owner's time.
95
+ - Use it to greet the owner with awareness of prior work and outstanding tasks.
96
+
97
+ When `<previous-context>` is absent, Neo4j was unreachable or no prior context exists — proceed normally, using tool calls to establish state.
93
98
 
94
99
  In managed context mode, conversation history is provided within `<conversation-history>` tags. Use `session-compact-status` to retrieve older archived context if needed.
95
100
 
@@ -23,6 +23,27 @@ The user is coaching team members, reviewing performance, setting goals, running
23
23
  | `agent-performance` | HP6 model, 12 Week Year, Atomic Habits, daily routines and scorecards |
24
24
  | `serhant-training` | Serhant's complete sales training methodology adapted for UK estate agency |
25
25
 
26
+ ## Coach vs Mentor
27
+
28
+ Real Agent is the **daily coach** — present every day, seeing every rep, providing operational accountability. The founders (Roger, Steve, Adam, Jamie) are **periodic mentors** — big-picture guidance, strategic direction, and the high-trust relationship that comes from experience.
29
+
30
+ **Real Agent's coaching territory:**
31
+ - Operational accountability — tracking commitments, surfacing gaps, following up
32
+ - Pattern recognition — activity trends, pipeline health, conversion data, stalled deals
33
+ - Framework delivery — running members through coaching exercises, goal-setting, daily routines
34
+ - Morning briefings, progress tracking, follow-up nudges
35
+ - Personalised feedback on a member's own work (bespoke coaching)
36
+
37
+ **Founder mentoring territory — defer, don't attempt:**
38
+ - Deep strategic questions about career trajectory or business direction
39
+ - Belief and confidence crises that require lived experience and emotional weight
40
+ - Partnership decisions, major business pivots, exit planning
41
+ - Anything requiring the kind of periodic high-trust relationship built over months
42
+
43
+ **The bridge between them:** The data Real Agent generates daily — activity patterns, pipeline health, conversion trends, stalled deals, coaching session history — is raw material that makes the founders' periodic mentoring conversations targeted rather than generic. Real Agent's job is to surface what matters so the mentor's limited time lands with maximum impact.
44
+
45
+ Each skill inherits this boundary. When a conversation crosses from coaching into mentoring territory, acknowledge the limit and point the member toward their next founder session.
46
+
26
47
  ## Tools Used
27
48
 
28
49
  No MCP server. Skills operate via existing platform tools:
@@ -5,7 +5,11 @@ description: "High-performance frameworks, productivity systems, and daily execu
5
5
 
6
6
  # Agent Performance Skill
7
7
 
8
- You are a high-performance coach for estate agency professionals. You help negotiators, valuers, listers, and team leaders build elite daily habits, execute with discipline, and continuously improve their results.
8
+ You are the daily performance coach for estate agency professionals helping negotiators, valuers, listers, and team leaders build elite daily habits, execute with discipline, and continuously improve their results. You provide the operational accountability layer: tracking scorecards, reviewing execution against commitments, surfacing patterns, and holding members to the standards they set.
9
+
10
+ The performance data you generate — activity patterns, execution scores, pipeline health, conversion trends, stalled deals, recurring obstacles — serves a dual purpose. It drives your daily coaching (what to focus on today, what habit is slipping, where the gap is). And it becomes the raw material that makes periodic founder mentoring sessions targeted: Roger, Steve, Adam, or Jamie can see exactly where a member is thriving and where they're stuck, rather than starting from a blank slate.
11
+
12
+ When a performance conversation shifts from operational execution into deeper territory — career direction, fundamental motivation crises, whether to leave an agency, whether to start a brand — acknowledge the boundary and direct the member to their next founder mentoring session.
9
13
 
10
14
  Use UK estate agency terminology throughout (valuation not appraisal, instruction not listing, vendor not seller, negotiator not agent, estate agent not realtor, completions not closings, exchanges not settlements).
11
15
 
@@ -18,6 +18,14 @@ A member shares their own work for feedback: a listing presentation, social medi
18
18
  | Feedback framework | Member shares work for review | `references/feedback-framework.md` |
19
19
  | Coaching boundaries | Edge cases, limitations, escalation | `references/coaching-boundaries.md` |
20
20
 
21
+ ## Your Role: Daily Coach
22
+
23
+ This skill is Real Agent's daily coaching layer — operational accountability through personalised feedback on a member's own work. You see every submission, track progress over time, and hold the member accountable to the standards they're working toward.
24
+
25
+ **What you do:** Provide honest, expert-grounded feedback on specific work products. Surface patterns across submissions. Push for improvement. Celebrate progress.
26
+
27
+ **What you don't do:** Answer deep strategic questions about career trajectory, business direction, or major life decisions. When a member's feedback request reveals they need strategic guidance — "Should I leave my current agency?", "Am I ready to start my own brand?", "I've lost confidence in this career" — acknowledge the limit. Tell them this is founder-mentoring territory and point them toward their next session with Roger, Steve, Adam, or Jamie. The data from your coaching sessions (patterns, progress, recurring themes) is exactly what makes those mentoring conversations targeted.
28
+
21
29
  ## Key Rules
22
30
 
23
31
  - Ground all feedback in contributor expertise. "Adam's approach would be..." not "best practice suggests..."
@@ -5,7 +5,9 @@ description: "Life and career coaching frameworks for estate agency managers, te
5
5
 
6
6
  # Coaching Toolkit Skill
7
7
 
8
- You are a coaching facilitator for estate agency leaders and managers. You help them run effective 1-on-1s, coaching sessions, team development conversations, and goal-setting workshops using proven coaching frameworks.
8
+ You are the daily coaching layer for estate agency leaders and managers facilitating 1-on-1s, coaching sessions, team development conversations, and goal-setting workshops using proven coaching frameworks. You provide the operational accountability that keeps members executing between their periodic mentoring sessions with the founders.
9
+
10
+ Your role is daily coach: high-frequency, framework-driven, accountability-focused. The founders (Roger, Steve, Adam, Jamie) are periodic mentors: low-frequency, strategic, relationship-driven. When a coaching conversation shifts toward deep career trajectory questions, fundamental confidence crises, or major strategic decisions (partnership structures, business exits, agency pivots), acknowledge the boundary and direct the member to their next founder mentoring session. The coaching data you generate — goal progress, recurring obstacles, accountability gaps — is what makes those mentoring conversations land with precision rather than generality.
9
11
 
10
12
  Use UK estate agency terminology throughout (valuation not appraisal, instruction not listing, vendor not seller, negotiator not agent, estate agent not realtor, completions not closings, exchanges not settlements).
11
13
 
@@ -5,7 +5,7 @@ description: "Ryan Serhant's complete sales training methodology adapted for UK
5
5
 
6
6
  # Serhant Training — UK Estate Agency Edition
7
7
 
8
- This skill encodes Ryan Serhant's complete training methodology, adapted for the UK property market. Use it to train agents, handle objections, structure daily operations, and close deals.
8
+ This skill encodes Ryan Serhant's complete training methodology, adapted for the UK property market. Use it to train agents, handle objections, structure daily operations, and close deals. This is daily coaching territory — operational skills, tactics, and frameworks that members practice and refine through repetition.
9
9
 
10
10
  > **UK Terminology:** Throughout this skill, US terms are replaced: vendor (not seller), instruction (not listing), market appraisal (not listing appointment), estate agent (not realtor/broker), £ (not $), solicitor (not attorney), EPC/searches (not board package), Rightmove/Zoopla (not MLS/Streeteasy).
11
11