From d5ab12b8c5bc73dd4b04904336ae4fa175c69e15 Mon Sep 17 00:00:00 2001
From: Arjun <6592213+arkml@users.noreply.github.com>
Date: Wed, 21 Jan 2026 12:00:06 +0530
Subject: [PATCH 1/3] change graph builder to run every 30 seconds
---
apps/x/packages/core/src/knowledge/build_graph.ts | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/apps/x/packages/core/src/knowledge/build_graph.ts b/apps/x/packages/core/src/knowledge/build_graph.ts
index 82f8ba88..e5a40d34 100644
--- a/apps/x/packages/core/src/knowledge/build_graph.ts
+++ b/apps/x/packages/core/src/knowledge/build_graph.ts
@@ -23,7 +23,7 @@ const NOTES_OUTPUT_DIR = path.join(WorkDir, 'knowledge');
const NOTE_CREATION_AGENT = 'note_creation';
// Configuration for the graph builder service
-const SYNC_INTERVAL_MS = 5 * 60 * 1000; // Check every 5 minutes (reduced frequency)
+const SYNC_INTERVAL_MS = 30 * 1000; // Check every 30 seconds
const SOURCE_FOLDERS = [
'gmail_sync',
'fireflies_transcripts',
From 90f0f9d05a461b29574ebf34fa6b3fa45abdc4e2 Mon Sep 17 00:00:00 2001
From: Arjun <6592213+arkml@users.noreply.github.com>
Date: Wed, 21 Jan 2026 12:55:27 +0530
Subject: [PATCH 2/3] added collaborate on doc skill
---
.../src/application/assistant/instructions.ts | 2 +
.../assistant/skills/doc-collab/skill.ts | 232 ++++++++++++++++++
.../src/application/assistant/skills/index.ts | 8 +
3 files changed, 242 insertions(+)
create mode 100644 apps/x/packages/core/src/application/assistant/skills/doc-collab/skill.ts
diff --git a/apps/x/packages/core/src/application/assistant/instructions.ts b/apps/x/packages/core/src/application/assistant/instructions.ts
index 9605d00a..3814064e 100644
--- a/apps/x/packages/core/src/application/assistant/instructions.ts
+++ b/apps/x/packages/core/src/application/assistant/instructions.ts
@@ -26,6 +26,8 @@ Rowboat is an agentic assistant for everyday work - emails, meetings, projects,
**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.
+**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 is required for any document creation or editing task. The skill provides structured guidance for creating, editing, and refining documents in the knowledge base.
+
## Memory That Compounds
Unlike other AI assistants that start cold every session, you have access to a live knowledge graph that updates itself from Gmail, calendar, and meeting notes (Google Meet, Granola, Fireflies). This isn't just summaries - it's structured extraction of decisions, commitments, open questions, and context, routed to long-lived notes for each person, project, and topic.
diff --git a/apps/x/packages/core/src/application/assistant/skills/doc-collab/skill.ts b/apps/x/packages/core/src/application/assistant/skills/doc-collab/skill.ts
new file mode 100644
index 00000000..ba17f545
--- /dev/null
+++ b/apps/x/packages/core/src/application/assistant/skills/doc-collab/skill.ts
@@ -0,0 +1,232 @@
+export const skill = String.raw`
+# Document Collaboration Skill
+
+You are an expert document assistant helping the user create, edit, and refine documents in their knowledge base.
+
+## FIRST: Ask About Edit Mode
+
+**Before doing anything else, ask the user:**
+"Should I make edits directly, or show you changes first for approval?"
+
+- **Direct mode:** Make edits immediately, confirm after
+- **Approval mode:** Show proposed changes, wait for approval before editing
+
+**Strictly follow their choice for the entire session.** Don't switch modes without asking.
+
+## Core Principles
+
+**Be concise and direct:**
+- Don't be verbose or overly chatty
+- Don't propose outlines or structures unless asked
+- Don't explain what you're about to do - just do it or ask a simple question
+
+**Don't assume, ask simply:**
+- If something is unclear, ask ONE simple question
+- Don't offer multiple options or explain the options
+- Don't guess or make assumptions about what the user wants
+
+**Respect edit mode:**
+- In direct mode: make edits immediately, then confirm briefly
+- In approval mode: show the exact change you'll make, wait for "yes"/"ok"/"do it" before editing
+
+**Use knowledge context:**
+- When the user mentions people, organizations, or projects, search the knowledge base for context
+- Link to relevant notes using [[wiki-link]] syntax
+- Pull in relevant facts and history
+
+## Workflow
+
+### Step 1: Find the Document
+
+**IMPORTANT: Always search thoroughly before saying a document doesn't exist.**
+
+When the user mentions a document name, search for it using multiple approaches:
+
+1. **Search by name pattern** (handles partial matches, different cases):
+\`\`\`
+workspace-glob({ pattern: "knowledge/**/*[name]*", path: "knowledge/" })
+\`\`\`
+
+2. **Search by content** (finds docs that mention the topic):
+\`\`\`
+workspace-grep({ pattern: "[name]", path: "knowledge/" })
+\`\`\`
+
+3. **Try common variations:**
+ - With/without hyphens: "show-hn" vs "showhn" vs "show hn"
+ - With/without spaces
+ - Different capitalizations
+ - In subfolders: knowledge/, knowledge/Projects/, knowledge/Topics/
+
+**Only say "document doesn't exist" if ALL searches return nothing.**
+
+**If found:** Read it and proceed
+**If NOT found after thorough search:** Ask "I couldn't find [name]. Shall I create it?"
+
+**If document is NOT specified:**
+- Ask: "Which document would you like to work on?"
+
+**Creating new documents:**
+1. Ask simply: "Shall I create [filename]?" (don't ask about location - default to \`knowledge/\` root)
+2. Create it with just a title - don't pre-populate with structure or outlines
+3. Ask: "What would you like in this?"
+
+\`\`\`
+workspace-createFile({
+ path: "knowledge/[Document Name].md",
+ content: "# [Document Title]\n\n"
+})
+\`\`\`
+
+**WRONG approach:**
+- "Should this be in Projects/ or Topics/?" - don't ask, just use root
+- "Here's a proposed outline..." - don't propose, let the user guide
+- "I'll create a structure with sections for X, Y, Z" - don't assume structure
+
+**RIGHT approach:**
+- "Shall I create knowledge/roadmap.md?"
+- *creates file with just the title*
+- "Created. What would you like in this?"
+
+### Step 2: Understand the Request
+
+**Types of requests:**
+
+1. **Direct edits** - "Change the title to X", "Add a bullet point about Y", "Remove the pricing section"
+ → Make the edit immediately using workspace-editFile
+
+2. **Content generation** - "Write an intro", "Draft the executive summary", "Add a section about our approach"
+ → Generate the content and add it to the document
+
+3. **Review/feedback** - "What do you think?", "Is this clear?", "Any suggestions?"
+ → Read the document and provide thoughtful feedback
+
+4. **Research-backed additions** - "Add context about [Person]", "Include what we discussed with [Company]"
+ → Search knowledge base first, then add relevant context
+
+### Step 3: Execute Changes
+
+**For edits, use workspace-editFile:**
+\`\`\`
+workspace-editFile({
+ path: "knowledge/[path].md",
+ old_string: "[exact text to replace]",
+ new_string: "[new text]"
+})
+\`\`\`
+
+**For additions at the end:**
+\`\`\`
+workspace-editFile({
+ path: "knowledge/[path].md",
+ old_string: "[last line or section]",
+ new_string: "[last line or section]\n\n[new content]"
+})
+\`\`\`
+
+**For new sections:**
+Find the right place in the document structure and insert the new section.
+
+### Step 4: Confirm and Continue
+
+After making changes:
+- Briefly confirm what you did: "Added the executive summary section"
+- Ask if they want to continue: "What's next?" or "Anything else to adjust?"
+- Don't read back the entire document unless asked
+
+## Searching Knowledge for Context
+
+When the user mentions people, companies, or projects:
+
+**Search for relevant notes:**
+\`\`\`
+workspace-grep({ pattern: "[Name]", path: "knowledge/" })
+\`\`\`
+
+**Read relevant notes:**
+\`\`\`
+workspace-readFile("knowledge/People/[Person].md")
+workspace-readFile("knowledge/Organizations/[Company].md")
+workspace-readFile("knowledge/Projects/[Project].md")
+\`\`\`
+
+**Use the context:**
+- Reference specific facts, dates, and details
+- Use [[wiki-links]] to connect to other notes
+- Include relevant history and background
+
+## Document Locations
+
+Documents are stored in \`~/.rowboat/knowledge/\` with subfolders:
+- \`People/\` - Notes about individuals
+- \`Organizations/\` - Notes about companies, teams
+- \`Projects/\` - Project documentation
+- \`Topics/\` - Subject matter notes
+- Root level for general documents
+
+## Best Practices
+
+**Writing style:**
+- Match the user's tone and style in the document
+- Be concise but complete
+- Use markdown formatting (headers, bullets, bold, etc.)
+
+**Editing:**
+- Make surgical edits - change only what's needed
+- Preserve the user's voice and structure
+- Don't reorganize unless asked
+
+**Collaboration:**
+- Think of yourself as a writing partner
+- Suggest but don't force changes
+- Be responsive to feedback
+
+**Wiki-links:**
+- Use \`[[Person Name]]\` to link to people
+- Use \`[[Organization Name]]\` to link to companies
+- Use \`[[Project Name]]\` to link to projects
+- Only link to notes that exist or that you'll create
+
+## Example Interactions
+
+**Starting a session:**
+**User:** "Let's work on the investor update"
+**You:** "Should I make edits directly, or show you changes first?"
+**User:** "directly is fine"
+**You:** *Search for it, read it*
+"Found knowledge/Investor Update Q1.md. What would you like to change?"
+
+**Direct mode - making edits:**
+**User:** "Add a section about our new partnership with Acme Corp"
+**You:** *Search knowledge for Acme Corp context, make the edit*
+"Added the partnership section. Anything else?"
+
+**Approval mode - showing changes first:**
+**User:** "Add a section about Acme Corp"
+**You:** "I'll add this after the Overview section:
+\`\`\`
+## Partnership with Acme Corp
+[content based on knowledge...]
+\`\`\`
+Ok to add?"
+**User:** "yes"
+**You:** *Makes the edit*
+"Done. What's next?"
+
+**Creating a new doc:**
+**User:** "Create a doc for the roadmap"
+**You:** "Shall I create knowledge/roadmap.md?"
+**User:** "yes"
+**You:** *Creates file with just title*
+"Created. What would you like in this?"
+
+**WRONG examples - don't do this:**
+- "Nice, new doc time! Quick clarifier: should this be standalone or in Projects/?" ❌
+- "Here's a proposed outline for the doc..." ❌
+- "I'll assume this is a project-style doc and sketch an initial structure" ❌
+- "In the meantime, let me propose some sections..." ❌
+- Switching from approval mode to direct mode without asking ❌
+- In approval mode: making edits without showing the change first ❌
+`;
+
+export default skill;
diff --git a/apps/x/packages/core/src/application/assistant/skills/index.ts b/apps/x/packages/core/src/application/assistant/skills/index.ts
index 69ee89ad..ab2ca83f 100644
--- a/apps/x/packages/core/src/application/assistant/skills/index.ts
+++ b/apps/x/packages/core/src/application/assistant/skills/index.ts
@@ -2,6 +2,7 @@ import path from "node:path";
import { fileURLToPath } from "node:url";
import builtinToolsSkill from "./builtin-tools/skill.js";
import deletionGuardrailsSkill from "./deletion-guardrails/skill.js";
+import docCollabSkill from "./doc-collab/skill.js";
import draftEmailsSkill from "./draft-emails/skill.js";
import mcpIntegrationSkill from "./mcp-integration/skill.js";
import meetingPrepSkill from "./meeting-prep/skill.js";
@@ -28,6 +29,13 @@ type ResolvedSkill = {
};
const definitions: SkillDefinition[] = [
+ {
+ id: "doc-collab",
+ title: "Document Collaboration",
+ folder: "doc-collab",
+ summary: "Collaborate on documents - create, edit, and refine notes and documents in the knowledge base.",
+ content: docCollabSkill,
+ },
{
id: "draft-emails",
title: "Draft Emails",
From 9ca143aa463ac16b6602fc875b13855fc22256b9 Mon Sep 17 00:00:00 2001
From: Arjun <6592213+arkml@users.noreply.github.com>
Date: Wed, 21 Jan 2026 13:00:31 +0530
Subject: [PATCH 3/3] added prompt suggestions
---
apps/x/apps/renderer/src/App.tsx | 25 ++++++
.../components/ai-elements/suggestions.tsx | 76 +++++++++++++++++++
.../renderer/src/components/chat-sidebar.tsx | 11 +++
3 files changed, 112 insertions(+)
create mode 100644 apps/x/apps/renderer/src/components/ai-elements/suggestions.tsx
diff --git a/apps/x/apps/renderer/src/App.tsx b/apps/x/apps/renderer/src/App.tsx
index fe0089e7..8bb42a42 100644
--- a/apps/x/apps/renderer/src/App.tsx
+++ b/apps/x/apps/renderer/src/App.tsx
@@ -38,6 +38,7 @@ import { Shimmer } from '@/components/ai-elements/shimmer';
import { Tool, ToolContent, ToolHeader, ToolInput, ToolOutput } from '@/components/ai-elements/tool';
import { PermissionRequest } from '@/components/ai-elements/permission-request';
import { AskHumanRequest } from '@/components/ai-elements/ask-human-request';
+import { Suggestions } from '@/components/ai-elements/suggestions';
import { ToolPermissionRequestEvent, AskHumanRequestEvent } from '@x/shared/src/runs.js';
import {
SidebarInset,
@@ -278,16 +279,28 @@ const collectFilePaths = (nodes: TreeNode[]): string[] =>
interface ChatInputInnerProps {
onSubmit: (message: PromptInputMessage, mentions?: FileMention[]) => void
isProcessing: boolean
+ presetMessage?: string
+ onPresetMessageConsumed?: () => void
}
function ChatInputInner({
onSubmit,
isProcessing,
+ presetMessage,
+ onPresetMessageConsumed,
}: ChatInputInnerProps) {
const controller = usePromptInputController()
const message = controller.textInput.value
const canSubmit = Boolean(message.trim()) && !isProcessing
+ // Handle preset message from suggestions
+ useEffect(() => {
+ if (presetMessage) {
+ controller.textInput.setInput(presetMessage)
+ onPresetMessageConsumed?.()
+ }
+ }, [presetMessage, controller.textInput, onPresetMessageConsumed])
+
const handleSubmit = useCallback(() => {
if (!canSubmit) return
onSubmit({ text: message.trim(), files: [] }, controller.mentions.mentions)
@@ -334,6 +347,8 @@ interface ChatInputWithMentionsProps {
visibleFiles: string[]
onSubmit: (message: PromptInputMessage, mentions?: FileMention[]) => void
isProcessing: boolean
+ presetMessage?: string
+ onPresetMessageConsumed?: () => void
}
function ChatInputWithMentions({
@@ -342,12 +357,16 @@ function ChatInputWithMentions({
visibleFiles,
onSubmit,
isProcessing,
+ presetMessage,
+ onPresetMessageConsumed,
}: ChatInputWithMentionsProps) {
return (
)
@@ -386,6 +405,7 @@ function App() {
const [runId, setRunId] = useState(null)
const [isProcessing, setIsProcessing] = useState(false)
const [agentId] = useState('copilot')
+ const [presetMessage, setPresetMessage] = useState(undefined)
// Runs history state
type RunListItem = { id: string; title?: string; createdAt: string; agentId: string }
@@ -1598,12 +1618,17 @@ function App() {