moved assistant to use skills; added agent monitoring

This commit is contained in:
Arjun 2025-11-16 11:36:50 +05:30
parent 80dae17fd1
commit 144bbe5878
7 changed files with 396 additions and 157 deletions

View file

@ -0,0 +1,24 @@
export const skill = String.raw`
# Deletion Guardrails
Load this skill when a user asks to delete agents or workflows so you follow the required confirmation steps.
## Workflow deletion protocol
1. Read the workflow file to identify every agent it references.
2. Report those agents to the user and ask whether they should be deleted too.
3. Wait for explicit confirmation before deleting anything.
4. Only remove the workflow and/or agents the user authorizes.
## Agent deletion protocol
1. Inspect the agent file to discover which workflows reference it.
2. List those workflows to the user and ask whether they should be updated or deleted.
3. Pause for confirmation before modifying workflows or removing the agent.
4. Perform only the deletions the user approves.
## Safety checklist
- Never delete cascaded resources automatically.
- Keep a clear audit trail in your responses describing what was removed.
- If the users instructions are ambiguous, ask clarifying questions before taking action.
`;
export default skill;

View file

@ -0,0 +1,143 @@
import path from "node:path";
import { fileURLToPath } from "node:url";
import deletionGuardrailsSkill from "./deletion-guardrails/skill.js";
import mcpIntegrationSkill from "./mcp-integration/skill.js";
import workflowAuthoringSkill from "./workflow-authoring/skill.js";
import workflowRunOpsSkill from "./workflow-run-ops/skill.js";
const CURRENT_FILE = fileURLToPath(import.meta.url);
const CURRENT_DIR = path.dirname(CURRENT_FILE);
const CATALOG_PREFIX = "src/application/assistant/skills";
type SkillDefinition = {
id: string;
title: string;
folder: string;
summary: string;
content: string;
};
type ResolvedSkill = {
id: string;
catalogPath: string;
content: string;
};
const definitions: SkillDefinition[] = [
{
id: "workflow-authoring",
title: "Workflow Authoring",
folder: "workflow-authoring",
summary: "Creating or editing workflows/agents, validating schema rules, and keeping filenames aligned with JSON ids.",
content: workflowAuthoringSkill,
},
{
id: "mcp-integration",
title: "MCP Integration Guidance",
folder: "mcp-integration",
summary: "Listing MCP servers/tools and embedding their schemas in agent definitions.",
content: mcpIntegrationSkill,
},
{
id: "deletion-guardrails",
title: "Deletion Guardrails",
folder: "deletion-guardrails",
summary: "Following the confirmation process before removing workflows or agents and their dependencies.",
content: deletionGuardrailsSkill,
},
{
id: "workflow-run-ops",
title: "Workflow Run Operations",
folder: "workflow-run-ops",
summary: "Commands that list workflow runs, inspect paused executions, or manage cron schedules for workflows.",
content: workflowRunOpsSkill,
},
];
const skillEntries = definitions.map((definition) => ({
...definition,
catalogPath: `${CATALOG_PREFIX}/${definition.folder}/skill.ts`,
}));
const catalogSections = skillEntries.map((entry) => [
`## ${entry.title}`,
`- **Skill file:** \`${entry.catalogPath}\``,
`- **Use it for:** ${entry.summary}`,
].join("\n"));
export const skillCatalog = [
"# Rowboat Skill Catalog",
"",
"Use this catalog to see which specialized skills you can load. Each entry lists the exact skill file plus a short description of when it helps.",
"",
catalogSections.join("\n\n"),
].join("\n");
const normalizeIdentifier = (value: string) =>
value.trim().replace(/\\/g, "/").replace(/^\.\/+/, "");
const aliasMap = new Map<string, ResolvedSkill>();
const registerAlias = (alias: string, entry: ResolvedSkill) => {
const normalized = normalizeIdentifier(alias);
if (!normalized) return;
aliasMap.set(normalized, entry);
};
const registerAliasVariants = (alias: string, entry: ResolvedSkill) => {
const normalized = normalizeIdentifier(alias);
if (!normalized) return;
const variants = new Set<string>([normalized]);
if (/\.(ts|js)$/i.test(normalized)) {
variants.add(normalized.replace(/\.(ts|js)$/i, ""));
variants.add(
normalized.endsWith(".ts") ? normalized.replace(/\.ts$/i, ".js") : normalized.replace(/\.js$/i, ".ts"),
);
} else {
variants.add(`${normalized}.ts`);
variants.add(`${normalized}.js`);
}
for (const variant of variants) {
registerAlias(variant, entry);
}
};
for (const entry of skillEntries) {
const absoluteTs = path.join(CURRENT_DIR, entry.folder, "skill.ts");
const absoluteJs = path.join(CURRENT_DIR, entry.folder, "skill.js");
const resolvedEntry: ResolvedSkill = {
id: entry.id,
catalogPath: entry.catalogPath,
content: entry.content,
};
const baseAliases = [
entry.id,
entry.folder,
`${entry.folder}/skill`,
`${entry.folder}/skill.ts`,
`${entry.folder}/skill.js`,
`skills/${entry.folder}/skill.ts`,
`skills/${entry.folder}/skill.js`,
`${CATALOG_PREFIX}/${entry.folder}/skill.ts`,
`${CATALOG_PREFIX}/${entry.folder}/skill.js`,
absoluteTs,
absoluteJs,
];
for (const alias of baseAliases) {
registerAliasVariants(alias, resolvedEntry);
}
}
export const availableSkills = skillEntries.map((entry) => entry.id);
export function resolveSkill(identifier: string): ResolvedSkill | null {
const normalized = normalizeIdentifier(identifier);
if (!normalized) return null;
return aliasMap.get(normalized) ?? null;
}

View file

@ -0,0 +1,60 @@
export const skill = String.raw`
# MCP Integration Guidance
Load this skill whenever a user asks about external tools, MCP servers, or how to extend an agents capabilities.
## Key concepts
- MCP servers expose tools (web scraping, APIs, databases, etc.) declared in \`config/mcp.json\`.
- Agents reference MCP tools through the \`"tools"\` block by specifying \`type\`, \`name\`, \`description\`, \`mcpServerName\`, and a full \`inputSchema\`.
- Tool schemas can include optional property descriptions; only include \`"required"\` when parameters are mandatory.
## Operator actions
1. Use \`listMcpServers\` to enumerate configured servers.
2. Use \`listMcpTools\` for a server to understand the available operations and schemas.
3. Explain which MCP tools match the users needs before editing agent definitions.
4. When adding a tool to an agent, document what it does and ensure the schema mirrors the MCP definition.
## Example snippets to reference
- Firecrawl search (required param):
\`\`\`
"tools": {
"search": {
"type": "mcp",
"name": "firecrawl_search",
"description": "Search the web",
"mcpServerName": "firecrawl",
"inputSchema": {
"type": "object",
"properties": {
"query": {"type": "string", "description": "Search query"},
"limit": {"type": "number", "description": "Number of results"}
},
"required": ["query"]
}
}
}
\`\`\`
- ElevenLabs text-to-speech (no required array):
\`\`\`
"tools": {
"text_to_speech": {
"type": "mcp",
"name": "text_to_speech",
"description": "Generate audio from text",
"mcpServerName": "elevenLabs",
"inputSchema": {
"type": "object",
"properties": {
"text": {"type": "string"}
}
}
}
}
\`\`\`
## Safety reminders
- Only recommend MCP tools that are actually configured.
- Clarify any missing details (required parameters, server names) before modifying files.
`;
export default skill;

View file

@ -0,0 +1,63 @@
export const skill = String.raw`
# Workflow Authoring
Load this skill whenever a user wants to inspect, create, or update workflows or agents inside the Rowboat workspace.
## Workflow knowledge
- Workflows (\`workflows/*.json\`) orchestrate multiple agents and define their order through \`"steps"\`.
- Agents (\`agents/*.json\`) configure a single model, its instructions, and the MCP tools it may use.
- Tools can be Rowboat built-ins or MCP integrations declared in the agent definition.
## Workflow format
\`\`\`
{
"name": "workflow_name",
"description": "Description of the workflow",
"steps": [
{"type": "agent", "id": "agent_name"}
]
}
\`\`\`
## Agent format
\`\`\`
{
"name": "agent_name",
"description": "Description of the agent",
"model": "gpt-4.1",
"instructions": "Instructions for the agent",
"tools": {
"descriptive_tool_key": {
"type": "mcp",
"name": "actual_mcp_tool_name",
"description": "What the tool does",
"mcpServerName": "server_name_from_config",
"inputSchema": {
"type": "object",
"properties": {
"param1": {"type": "string", "description": "What the parameter means"}
}
}
}
}
}
\`\`\`
- Tool keys should be descriptive (e.g., \`"search"\`, \`"fetch"\`, \`"analyze"\`) rather than the MCP tool name.
- Include \`required\` in the \`inputSchema\` only when parameters are actually required.
## Naming and organization rules
- Agent filenames must match the \`"name"\` field and the workflow step \`"id"\`.
- Workflow filenames must match the \`"name"\` field.
- Agents live under \`agents/\`, workflows under \`workflows/\`—never place them elsewhere.
- Always keep filenames, \`"name"\`, and referenced ids perfectly aligned.
- Use relative paths (no \${BASE_DIR} prefixes) when calling tools from the CLI.
## Capabilities checklist
1. Explore the repository to understand existing workflows/agents before editing.
2. Update files carefully to maintain schema validity.
3. Suggest improvements and ask clarifying questions.
4. List and explore MCP servers/tools when users need new capabilities.
5. Confirm work done and outline next steps once changes are complete.
`;
export default skill;

View file

@ -0,0 +1,61 @@
export const skill = String.raw`
# Workflow Run Operations
Package of repeatable commands for inspecting workflow run history under ~/.rowboat/runs and managing cron schedules that trigger Rowboat workflows. Load this skill whenever a user asks about workflow run files, paused executions, or cron-based scheduling/unscheduling.
## When to use
- User wants to list or filter workflow runs (all runs, by workflow, time range, or paused for input).
- User wants to inspect cron jobs or change the workflow schedule.
- User asks how to set up monitoring for waiting runs or confirm a cron entry exists.
## Run monitoring examples
Operate from ~/.rowboat (Rowboat tools already set this as the working directory). Use executeCommand with the sample Bash snippets below, modifying placeholders as needed.
Each run file name starts with a timestamp like '2025-11-12T08-02-41Z'. You can use this to filter for date/time ranges.
Each line of the run file contains a running log with the first line containing informatin of the workflow. E.g. '{"type":"start","runId":"2025-11-12T08-02-41Z-0014322-000","workflowId":"exa-search","workflow":{"name":"example_workflow","description":"An example workflow","steps":[{"type":"agent","id":"exa-search"}]},"interactive":true,"ts":"2025-11-12T08:02:41.168Z"}'
If a run is waiting for human input the last line will contain 'paused_for_human_input'. See examples below.
1. **List all runs**
ls ~/.rowboat/runs
2. **Filter by workflow**
grep -rl '"workflowId":"<workflow-id>"' ~/.rowboat/runs | xargs -n1 basename | sed 's/\.jsonl$//' | sort -r
Replace <workflow-id> with the desired id.
3. **Filter by time window**
To the previous commands add the below through unix pipe
awk -F'/' '$NF >= "2025-11-12T08-03" && $NF <= "2025-11-12T08-10"'
Use the correct timestamps.
4. **Show runs waiting for human input**
awk 'FNR==1{if (NR>1) print fn, last; fn=FILENAME} {last=$0} END{print fn, last}' ~/.rowboat/runs/*.jsonl | grep 'pause-for-human-input' | awk '{print $1}'
Prints the files whose last line equals 'pause-for-human-input'.
## Cron management examples
1. **View current cron schedule**
bash -lc "crontab -l 2>/dev/null || echo 'No crontab entries configured for this user.'"
2. **Schedule a new workflow**
crontab -l 2>/dev/null; echo '0 10 * * * /usr/local/bin/node dist/app.js exa-search "what is the weather in tokyo" >> /Users/arjun/.rowboat/logs/exa_search.log 2>&1' ) | crontab -
3. **Unschedule/remove a workflow**
crontab -l | grep -v 'exa-search' | crontab -
Removes cron lines containing the workflow id.
`;
export default skill;