mirror of
https://github.com/rowboatlabs/rowboat.git
synced 2026-07-12 21:02:17 +02:00
feat(x): regroup copilot prompt guidance into skills
Capability guidance now co-locates with the tools that skills own: - Register the previously orphaned slack skill in the catalog (excluded when Slack isn't connected, like composio-integration) and shrink the prompt's Slack block to a routing line + followed-channels hint — the agent-slack command patterns already live in the skill body. - Compress the per-capability routing directives (meeting-prep, create-presentations, doc-collab, app-navigation, background-task, apps, browser-control, notify-user) to when-to-load signals; the how-to detail loads with each skill. - Slim the knowledge-graph access examples to the essential patterns. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
parent
2e45035ece
commit
2ab3e4e751
2 changed files with 26 additions and 41 deletions
|
|
@ -79,11 +79,13 @@ function buildStaticInstructions(composioEnabled: boolean, catalog: string, code
|
|||
// Slack is connected directly in Rowboat (agent-slack CLI), independent of
|
||||
// Composio. Route every Slack request to the native \`slack\` skill so the
|
||||
// Copilot never claims Slack isn't connected or sends it through Composio.
|
||||
// Channel names are per-user config, so they stay in the prompt; the
|
||||
// agent-slack command patterns live in the `slack` skill body.
|
||||
const slackChannelsLine = slackChannelsHint
|
||||
? ` The user has selected these Slack channels to follow: ${slackChannelsHint}. For broad "what's on my Slack / catch me up / anything new" requests, query THESE channels directly with \`agent-slack message list "#channel" --workspace <url> --oldest <unix-seconds> --limit 100 --resolve-users\` (use \`--oldest\`/\`--latest\` to scope to today/yesterday). Do NOT rely on \`search messages\` or \`unreads\` to answer catch-up questions — they frequently return empty with desktop-imported auth even when channels have messages; direct \`message list\` is authoritative.`
|
||||
? ` The user's followed channels: ${slackChannelsHint}.`
|
||||
: '';
|
||||
const slackBlock = slackConnected
|
||||
? `\n**Slack (connected):** Slack is connected directly in Rowboat (via the agent-slack CLI, not Composio). For ANY Slack request — summarizing or reading messages, catching up on channels or DMs, searching, listing users, or sending a message — your FIRST action MUST be \`loadSkill('slack')\`, then use the \`agent-slack\` commands it documents via \`executeCommand\` (the selected workspaces are in \`config/slack.json\`). NEVER tell the user Slack isn't connected, and NEVER route Slack through the \`composio-integration\` skill.${slackChannelsLine}\n`
|
||||
? `\n**Slack (connected):** For ANY Slack request — reading, catching up, searching, or sending — your FIRST action MUST be \`loadSkill('slack')\`. Slack is connected natively via the agent-slack CLI: NEVER tell the user it isn't connected, and NEVER route Slack through Composio.${slackChannelsLine}\n`
|
||||
: '';
|
||||
|
||||
const slackToolPriority = slackConnected
|
||||
|
|
@ -131,23 +133,19 @@ Rowboat is an agentic assistant for everyday work - emails, meetings, projects,
|
|||
|
||||
**Email Drafting:** When users ask you to **draft** or **compose** emails (e.g., "draft a follow-up to Monica", "write an email to John about the project"), load the \`draft-emails\` skill first.${emailDraftSuffix}
|
||||
|
||||
${thirdPartyBlock}${gmailBlock}${slackBlock}**Meeting Prep:** When users ask you to prepare for a meeting, prep for a call, or brief them on attendees, load the \`meeting-prep\` skill first. It provides structured guidance for gathering context about attendees from the knowledge base and creating useful meeting briefs.
|
||||
${thirdPartyBlock}${gmailBlock}${slackBlock}**Meeting Prep:** When users ask you to prepare for a meeting, prep for a call, or brief them on attendees, load the \`meeting-prep\` skill first.
|
||||
|
||||
**Create Presentations:** When users ask you to create a presentation, slide deck, pitch deck, or PDF slides, load the \`create-presentations\` skill first. It provides structured guidance for generating PDF presentations using context from the knowledge base.
|
||||
**Create Presentations:** When users ask you to create a presentation, slide deck, pitch deck, or PDF slides, load the \`create-presentations\` skill first.
|
||||
|
||||
**Document Collaboration:** When users ask you to work on a document, collaborate on writing, create a new document, edit/refine existing notes, or say things like "let's work on [X]", "help me write [X]", "create a doc for [X]", or "let's draft [X]", you MUST load the \`doc-collab\` skill first. **This applies even for small one-off edits** — the skill carries the canonical *terse-and-scannable* writing style for the knowledge base, and that style applies whether you're authoring a fresh note or fixing a single section. Load it before writing anything into a note.
|
||||
**Document Collaboration:** For ANY writing into a knowledge-base note — creating, editing, or refining, **even small one-off edits** ("let's work on [X]", "help me write [X]", "create a doc for [X]") — you MUST load the \`doc-collab\` skill first; it carries the canonical writing style for the knowledge base.
|
||||
|
||||
${codeModeEnabled
|
||||
? `**Code with Agents:** When users ask you to write code, build a project, create a script, fix a bug, or do any software development task — **including simple things like "create a .c file" or "write a hello-world in Python"** — your FIRST action MUST be \`loadSkill('code-with-agents')\`. Do NOT reach for \`executeCommand\` (PowerShell / bash / shell) or any workspace file tool to do code work yourself before loading this skill. The skill decides whether to delegate to Claude Code / Codex (via acpx) or hand control back to you, and it presents the user a one-click choice when needed. Paths outside the Rowboat workspace root (e.g. \`G:/...\`, \`~/projects/...\`) are NORMAL for coding tasks — do NOT raise "outside workspace" concerns or fall back to your own tools.`
|
||||
: `**Code with Agents (disabled):** Code mode is currently OFF in the user's settings. Do NOT load \`code-with-agents\` and do NOT call acpx. Handle coding requests yourself with your normal tools if you can. After answering, add a final line letting the user know they can delegate coding to Claude Code or Codex by enabling Code Mode in Settings → Code Mode.`}
|
||||
|
||||
**App Control (drive the app):** You can drive the Rowboat UI the user is looking at — open any view (email, meetings, background agents, chat history, knowledge, workspace, code, bases, graph), READ what a view contains (\`read-view\` returns emails / background agents / past chats as data while showing the view on screen), and open specific items (an email thread, a note, an agent, a past chat). When users ask to open, show, find, or ask about anything that lives inside Rowboat, load the \`app-navigation\` skill first — it documents the show-while-telling pattern. This matters most on calls: navigate so the user sees what you see, then answer briefly.
|
||||
**App Control (drive the app):** You can drive the Rowboat UI the user is looking at — open any view, READ what a view contains as data, and open specific items (an email thread, a note, an agent, a past chat). When users ask to open, show, find, or ask about anything that lives inside Rowboat, load the \`app-navigation\` skill first. This matters most on calls: navigate so the user sees what you see, then answer briefly.
|
||||
|
||||
**Background Tasks (Self-Running Work):** Rowboat can run *background tasks* — persistent instructions the agent fires on a schedule and/or in response to incoming emails / calendar events. A bg-task either maintains a snapshot in its \`index.md\` (digest, dashboard, rolling summary) or performs a recurring side-effect (send a Slack message, draft an email, post to a webhook, call an API). This is the flagship surface for *anything recurring*.
|
||||
|
||||
*Strong signals (load the \`background-task\` skill, act without asking):* cadence words ("every morning / daily / hourly / each Monday…"), "keep a running summary of…", "maintain a digest of…", "watch / monitor / keep an eye on…", "send me X each morning…", "whenever a relevant email comes in, X…", action verbs ("draft / reply / call / post / notify / file / brief me on…"), "track / follow X".
|
||||
|
||||
*Medium signals (load the skill, answer the one-off, then offer):* one-off questions about decaying info ("what's the weather?", "top HN stories?"), "what's the latest on X / catch me up on X / any updates on X" about a person, company, project, or topic, recurring artifacts ("morning briefing", "weekly review", "Acme deal dashboard"). **Heuristic:** if you reach for \`web-search\` or a news tool to answer a recurring question, the answer is the kind of thing a bg-task would refresh on a schedule.
|
||||
**Background Tasks (Self-Running Work):** Rowboat runs *background tasks* — persistent instructions fired on a schedule and/or on incoming emails / calendar events; the flagship surface for *anything recurring*. Load the \`background-task\` skill and act without asking on cadence words ("every morning / daily / each Monday…"), "keep a running summary / digest of…", "watch / monitor…", "whenever a relevant email comes in, X…", "track / follow X". Load it and offer after answering when a one-off question is about decaying or recurring info ("catch me up on X", "morning briefing" — heuristic: if you reach for \`web-search\` to answer a recurring question, a bg-task should be refreshing it).
|
||||
|
||||
**Sub-Agents (parallel & heavy work):** The \`spawn-agent\` tool runs a sub-agent in its own isolated, headless thread and returns only its final answer — the sub-agent's tool calls, page fetches, and file reads never enter this conversation. Use it to keep this context clean: a sub-agent can read twenty notes or six web pages and hand you back one paragraph. Issue several spawn-agent calls in ONE response to run them in parallel.
|
||||
|
||||
|
|
@ -155,12 +153,12 @@ ${codeModeEnabled
|
|||
|
||||
*Do NOT spawn for:* single quick lookups (one file read, one search — just do it); tasks where the user wants to see the intermediate detail, not a distillation; anything needing user input mid-way (sub-agents run headless and cannot ask questions); driving the app UI or the embedded browser (those are shared surfaces you control, not sub-agents). Remember each sub-agent starts with ZERO context — its \`task\` must be fully self-contained (names, dates, constraints, expected output format).
|
||||
|
||||
**Rowboat Apps:** When users ask you to build/make/create an *app* or *dashboard* ("build me an app that…", "make a dashboard for…"), load the \`apps\` skill FIRST — it defines the app contract (manifest, dist/, Host API) and the build flow. For ambiguous requests that could be a one-off answer ("show me my open PRs"), the skill's intent gate says to confirm before building. Do not hand-roll app folders without the skill.
|
||||
**Rowboat Apps:** When users ask you to build/make/create an *app* or *dashboard*, load the \`apps\` skill FIRST — never hand-roll app folders without it. For ambiguous requests that could be a one-off answer ("show me my open PRs"), it says to confirm before building.
|
||||
|
||||
**Live Notes:** If the user explicitly says "live note" or "live-note", load the \`live-note\` skill. Otherwise, do not propose live notes — prefer the \`background-task\` skill for anything recurring.
|
||||
**Browser Control:** When users ask you to open a website, browse in-app, search the web in the embedded browser, or interact with a live webpage inside Rowboat, load the \`browser-control\` skill first. It explains the \`read-page -> indexed action -> refreshed page\` workflow for the browser pane.
|
||||
**Browser Control:** When users ask you to open a website, browse in-app, or interact with a live webpage inside Rowboat, load the \`browser-control\` skill first.
|
||||
|
||||
**Notifications:** When you need to send a desktop notification — completion alert after a long task, time-sensitive update, or a clickable result that lands the user on a specific note/view — load the \`notify-user\` skill first. It documents the \`notify-user\` tool and the \`rowboat://\` deep links you can attach to it.
|
||||
**Notifications:** To send a desktop notification — completion alert, time-sensitive update, or a clickable result that lands on a specific note/view — load the \`notify-user\` skill first.
|
||||
|
||||
|
||||
## Learning About the User (save-to-memory)
|
||||
|
|
@ -213,33 +211,10 @@ Users can interact with the knowledge graph through you, open it directly in Obs
|
|||
- **WRONG:** \`file-grep({ pattern: "John", searchPath: "" })\` or \`searchPath: "."\` or any absolute path to the workspace root
|
||||
- **CORRECT:** \`file-grep({ pattern: "John", searchPath: "knowledge/" })\`
|
||||
|
||||
Use the builtin file tools to search and read the knowledge base:
|
||||
|
||||
**Finding notes:**
|
||||
\`\`\`
|
||||
# List all people notes
|
||||
file-list("knowledge/People")
|
||||
|
||||
# Search for a person by name - MUST include knowledge/ in path
|
||||
file-grep({ pattern: "Sarah Chen", searchPath: "knowledge/" })
|
||||
|
||||
# Find notes mentioning a company - MUST include knowledge/ in path
|
||||
file-grep({ pattern: "Acme Corp", searchPath: "knowledge/" })
|
||||
\`\`\`
|
||||
|
||||
**Reading notes:**
|
||||
\`\`\`
|
||||
# Read a specific person's note
|
||||
file-readText("knowledge/People/Sarah Chen.md")
|
||||
|
||||
# Read an organization note
|
||||
file-readText("knowledge/Organizations/Acme Corp.md")
|
||||
\`\`\`
|
||||
|
||||
**When a user mentions someone by name:**
|
||||
1. First, search for them: \`file-grep({ pattern: "John", searchPath: "knowledge/" })\`
|
||||
2. Read their note to get full context: \`file-readText("knowledge/People/John Smith.md")\`
|
||||
3. Use the context (role, organization, past interactions, commitments) in your response
|
||||
Use the base file tools to search and read it:
|
||||
- Find: \`file-grep({ pattern: "Sarah Chen", searchPath: "knowledge/" })\`; list a category with \`file-list("knowledge/People")\`.
|
||||
- Read: \`file-readText("knowledge/People/Sarah Chen.md")\`.
|
||||
- When a user mentions someone by name: grep for them in \`knowledge/\`, read their note, and use that context (role, organization, past interactions, commitments) in your response.
|
||||
|
||||
**NEVER use an empty search path or root path for knowledge lookup. ALWAYS set searchPath to \`knowledge/\` or a subfolder like \`knowledge/People/\`.**
|
||||
|
||||
|
|
@ -437,6 +412,7 @@ export async function buildCopilotInstructions(): Promise<string> {
|
|||
const excludeIds: string[] = [];
|
||||
if (!composioEnabled) excludeIds.push('composio-integration');
|
||||
if (!codeModeEnabled) excludeIds.push('code-with-agents');
|
||||
if (!slackConnected) excludeIds.push('slack');
|
||||
// Always build from the live skill set so disk skills added/removed at
|
||||
// runtime (after refreshDiskSkills + cache invalidation) are reflected.
|
||||
const catalog = buildSkillCatalog({ excludeIds });
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ import liveNoteSkill from "./live-note/skill.js";
|
|||
import backgroundTaskSkill from "./background-task/skill.js";
|
||||
import notifyUserSkill from "./notify-user/skill.js";
|
||||
import appsSkill from "./apps/skill.js";
|
||||
import slackSkill from "./slack/skill.js";
|
||||
|
||||
const CURRENT_DIR = path.dirname(fileURLToPath(import.meta.url));
|
||||
const CATALOG_PREFIX = "src/application/assistant/skills";
|
||||
|
|
@ -176,6 +177,14 @@ const definitions: SkillDefinition[] = [
|
|||
content: browserControlSkill,
|
||||
tools: ["browser-control", "load-browser-skill"],
|
||||
},
|
||||
{
|
||||
// Excluded from the catalog when Slack isn't connected (see
|
||||
// buildCopilotInstructions excludeIds), mirroring composio-integration.
|
||||
id: "slack",
|
||||
title: "Slack",
|
||||
summary: "Read, search, and send Slack messages via the agent-slack CLI — catch up on channels, summarize threads, list users. Load FIRST for ANY Slack request; Slack is connected natively, never through Composio.",
|
||||
content: slackSkill,
|
||||
},
|
||||
{
|
||||
id: "notify-user",
|
||||
title: "Notify User",
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue