daemora 1.0.5 → 1.0.6

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/SOUL.md CHANGED
@@ -6,9 +6,11 @@ You are **Daemora** — the user's personal AI that lives on their machine. You'
6
6
 
7
7
  **You are an agent, not a chatbot.** When told to do something, do it. Don't describe what you would do. Don't ask if you should. Don't propose a plan and wait. Just do the work and come back with results.
8
8
 
9
- **You own it end-to-end.** Write the code, run the build, test it, fix what breaks. Don't hand work back incomplete. The task is done when it actually works not when you've made an attempt.
9
+ **You are fully autonomous.** Execute the entire task start to finish without stopping to ask the user. Use your tools, skills, commands, browser, MCP servers — whatever it takes. Only stop and ask when you hit a genuine blocker that requires a human decision (e.g. "which of these two designs do you prefer?" or "this requires a paid API key I don't have"). Everything else — figure it out yourself and keep going.
10
10
 
11
- **You figure things out.** Read the file. Check the context. Run the command. Search for it. Only ask when you genuinely need a decision from the user never ask about things you can discover yourself.
11
+ **You own it end-to-end.** Write the code, run the build, test it, fix what breaks. Send the email, fetch the data, create the document, deploy the change. Don't hand work back incomplete. The task is done when it actually works not when you've made an attempt.
12
+
13
+ **You figure things out.** Read the file. Check the context. Run the command. Search for it. Load a skill. Check memory. Only ask when you genuinely need a decision from the user — never ask about things you can discover yourself.
12
14
 
13
15
  **You talk like a person.** You're not a customer support bot. No "I'd be happy to help!" No "What can I help you with today?" No "I have successfully completed the task." Talk like a capable person who just did something — brief, natural, real. If someone says "hey", say "hey" back. If you sent an email, say what you told them, not the Message ID.
14
16
 
@@ -49,9 +51,9 @@ A task is complex if it involves:
49
51
 
50
52
  ---
51
53
 
52
- ## Coding - Full Ownership
54
+ ## Building & Coding - Full Ownership
53
55
 
54
- When you build something:
56
+ When you build or create something:
55
57
  1. **Plan first for complex tasks.** Use projectTracker to break complex work into steps before writing code.
56
58
  2. **Read before touching.** Never edit a file you haven't read in this session.
57
59
  3. **Build, don't describe.** Write the actual code with writeFile/editFile. Never describe what code would look like.
package/config/mcp.json CHANGED
@@ -24,29 +24,19 @@
24
24
  "_comment_memory": "Persistent memory via knowledge graph (no API key needed)",
25
25
  "memory": {
26
26
  "command": "npx",
27
- "args": [
28
- "-y",
29
- "@modelcontextprotocol/server-memory"
30
- ],
27
+ "args": ["-y", "@modelcontextprotocol/server-memory"],
31
28
  "enabled": false
32
29
  },
33
- "_comment_filesystem": "Secure file access (CHANGE the path to your workspace!)",
30
+ "_comment_filesystem": "Secure file access (set allowed directory paths in args)",
34
31
  "filesystem": {
35
32
  "command": "npx",
36
- "args": [
37
- "-y",
38
- "@modelcontextprotocol/server-filesystem",
39
- "/Users/you/Projects"
40
- ],
33
+ "args": ["-y", "@modelcontextprotocol/server-filesystem", "/Users/you/Projects"],
41
34
  "enabled": false
42
35
  },
43
36
  "_comment_github": "GitHub integration - repos, PRs, issues, commits",
44
37
  "github": {
45
38
  "command": "npx",
46
- "args": [
47
- "-y",
48
- "@modelcontextprotocol/server-github"
49
- ],
39
+ "args": ["-y", "@modelcontextprotocol/server-github"],
50
40
  "env": {
51
41
  "GITHUB_PERSONAL_ACCESS_TOKEN": "YOUR_GITHUB_TOKEN"
52
42
  },
@@ -55,72 +45,38 @@
55
45
  "_comment_brave": "Brave Search - web, news, image search",
56
46
  "brave-search": {
57
47
  "command": "npx",
58
- "args": [
59
- "-y",
60
- "@anthropic-ai/brave-search-mcp-server"
61
- ],
48
+ "args": ["-y", "@modelcontextprotocol/server-brave-search"],
62
49
  "env": {
63
50
  "BRAVE_API_KEY": "YOUR_BRAVE_API_KEY"
64
51
  },
65
52
  "enabled": false
66
53
  },
67
- "_comment_git": "Git operations - read, search, manipulate repos",
68
- "git": {
69
- "command": "npx",
70
- "args": [
71
- "-y",
72
- "@modelcontextprotocol/server-git"
73
- ],
74
- "enabled": false
75
- },
76
- "_comment_fetch": "Web fetching - convert web pages to LLM-friendly text",
77
- "fetch": {
78
- "command": "npx",
79
- "args": [
80
- "-y",
81
- "@modelcontextprotocol/server-fetch"
82
- ],
83
- "enabled": false
84
- },
85
54
  "_comment_slack": "Slack workspace integration",
86
55
  "slack": {
87
56
  "command": "npx",
88
- "args": [
89
- "-y",
90
- "@modelcontextprotocol/server-slack"
91
- ],
57
+ "args": ["-y", "@modelcontextprotocol/server-slack"],
92
58
  "env": {
93
59
  "SLACK_BOT_TOKEN": "",
94
60
  "SLACK_TEAM_ID": ""
95
61
  },
96
62
  "enabled": false
97
63
  },
98
- "_comment_postgres": "PostgreSQL database access",
64
+ "_comment_postgres": "PostgreSQL database access (read-only SQL)",
99
65
  "postgres": {
100
66
  "command": "npx",
101
- "args": [
102
- "-y",
103
- "@modelcontextprotocol/server-postgres",
104
- "postgresql://user:pass@localhost:5432/mydb"
105
- ],
67
+ "args": ["-y", "@modelcontextprotocol/server-postgres", "postgresql://user:pass@localhost:5432/mydb"],
106
68
  "enabled": false
107
69
  },
108
- "_comment_puppeteer": "Browser automation via Puppeteer",
70
+ "_comment_puppeteer": "Browser automation, screenshots, web interaction",
109
71
  "puppeteer": {
110
72
  "command": "npx",
111
- "args": [
112
- "-y",
113
- "@modelcontextprotocol/server-puppeteer"
114
- ],
73
+ "args": ["-y", "@modelcontextprotocol/server-puppeteer"],
115
74
  "enabled": false
116
75
  },
117
- "_comment_sentry": "Sentry error tracking integration",
76
+ "_comment_sentry": "Sentry error tracking - query issues, generate patches",
118
77
  "sentry": {
119
78
  "command": "npx",
120
- "args": [
121
- "-y",
122
- "@sentry/mcp-server@latest"
123
- ],
79
+ "args": ["-y", "@sentry/mcp-server@latest"],
124
80
  "env": {
125
81
  "SENTRY_AUTH_TOKEN": "YOUR_SENTRY_AUTH_TOKEN"
126
82
  },
@@ -129,17 +85,121 @@
129
85
  "_comment_sequential": "Sequential thinking - structured problem solving",
130
86
  "sequential-thinking": {
131
87
  "command": "npx",
132
- "args": [
133
- "-y",
134
- "@modelcontextprotocol/server-sequentialthinking"
135
- ],
88
+ "args": ["-y", "@modelcontextprotocol/server-sequential-thinking"],
89
+ "enabled": false
90
+ },
91
+ "_comment_notion": "Notion - pages, databases, search, comments",
92
+ "notion": {
93
+ "command": "npx",
94
+ "args": ["-y", "@notionhq/notion-mcp-server"],
95
+ "env": {
96
+ "NOTION_TOKEN": ""
97
+ },
98
+ "enabled": false
99
+ },
100
+ "_comment_linear": "Linear - issues, projects, teams, sprints",
101
+ "linear": {
102
+ "command": "npx",
103
+ "args": ["-y", "mcp-remote", "https://mcp.linear.app/mcp"],
104
+ "enabled": false
105
+ },
106
+ "_comment_hubspot": "HubSpot CRM - contacts, deals, companies, tickets",
107
+ "hubspot": {
108
+ "command": "npx",
109
+ "args": ["-y", "@hubspot/mcp-server"],
110
+ "env": {
111
+ "PRIVATE_APP_ACCESS_TOKEN": ""
112
+ },
113
+ "enabled": false
114
+ },
115
+ "_comment_stripe": "Stripe - payments, invoices, subscriptions, customers",
116
+ "stripe": {
117
+ "command": "npx",
118
+ "args": ["-y", "@stripe/mcp", "--tools=all"],
119
+ "env": {
120
+ "STRIPE_SECRET_KEY": ""
121
+ },
122
+ "enabled": false
123
+ },
124
+ "_comment_jira": "Jira - issues, projects, sprints, JQL search",
125
+ "jira": {
126
+ "command": "npx",
127
+ "args": ["-y", "@aashari/mcp-server-atlassian-jira"],
128
+ "env": {
129
+ "ATLASSIAN_SITE_NAME": "",
130
+ "ATLASSIAN_USER_EMAIL": "",
131
+ "ATLASSIAN_API_TOKEN": ""
132
+ },
133
+ "enabled": false
134
+ },
135
+ "_comment_confluence": "Confluence - spaces, pages, search, content",
136
+ "confluence": {
137
+ "command": "npx",
138
+ "args": ["-y", "@aashari/mcp-server-atlassian-confluence"],
139
+ "env": {
140
+ "ATLASSIAN_SITE_NAME": "",
141
+ "ATLASSIAN_USER_EMAIL": "",
142
+ "ATLASSIAN_API_TOKEN": ""
143
+ },
144
+ "enabled": false
145
+ },
146
+ "_comment_figma": "Figma - design data, layouts, styles, components",
147
+ "figma": {
148
+ "command": "npx",
149
+ "args": ["-y", "figma-developer-mcp", "--figma-api-key=YOUR_FIGMA_TOKEN", "--stdio"],
150
+ "enabled": false
151
+ },
152
+ "_comment_gdrive": "Google Drive - files, folders, search",
153
+ "gdrive": {
154
+ "command": "npx",
155
+ "args": ["-y", "@modelcontextprotocol/server-gdrive"],
156
+ "env": {
157
+ "GDRIVE_CREDENTIALS_PATH": ""
158
+ },
159
+ "enabled": false
160
+ },
161
+ "_comment_google_maps": "Google Maps - geocoding, directions, places, elevation",
162
+ "google-maps": {
163
+ "command": "npx",
164
+ "args": ["-y", "@modelcontextprotocol/server-google-maps"],
165
+ "env": {
166
+ "GOOGLE_MAPS_API_KEY": ""
167
+ },
168
+ "enabled": false
169
+ },
170
+ "_comment_firecrawl": "Firecrawl - web scraping, crawling, content extraction",
171
+ "firecrawl": {
172
+ "command": "npx",
173
+ "args": ["-y", "firecrawl-mcp"],
174
+ "env": {
175
+ "FIRECRAWL_API_KEY": ""
176
+ },
177
+ "enabled": false
178
+ },
179
+ "_comment_tavily": "Tavily - real-time web search, data extraction",
180
+ "tavily": {
181
+ "command": "npx",
182
+ "args": ["-y", "tavily-mcp@latest"],
183
+ "env": {
184
+ "TAVILY_API_KEY": ""
185
+ },
186
+ "enabled": false
187
+ },
188
+ "_comment_cloudflare": "Cloudflare - Workers, KV, R2, D1 management",
189
+ "cloudflare": {
190
+ "command": "npx",
191
+ "args": ["-y", "@cloudflare/mcp-server-cloudflare"],
136
192
  "enabled": false
137
193
  },
138
- "Umar": {
139
- "enabled": false,
140
- "url": "https://api.example.com/sse",
141
- "transport": "sse",
142
- "description": "kajshdkjahskdhaskdh"
194
+ "_comment_upstash": "Upstash - serverless Redis and message queues",
195
+ "upstash": {
196
+ "command": "npx",
197
+ "args": ["-y", "@upstash/mcp-server"],
198
+ "env": {
199
+ "UPSTASH_REDIS_REST_URL": "",
200
+ "UPSTASH_REDIS_REST_TOKEN": ""
201
+ },
202
+ "enabled": false
143
203
  }
144
204
  }
145
- }
205
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "daemora",
3
- "version": "1.0.5",
3
+ "version": "1.0.6",
4
4
  "description": "A powerful open-source AI agent that runs on your machine. Connects to any AI model, any MCP server, any channel. Fully autonomous - plans, codes, tests, browses, emails, and manages your tools without asking permission.",
5
5
  "main": "src/index.js",
6
6
  "bin": {
@@ -1,5 +1,5 @@
1
1
  import { runAgentLoop } from "../core/AgentLoop.js";
2
- import { buildSystemPrompt } from "../systemPrompt.js";
2
+ import { buildSystemPrompt } from "./systemPrompt.js";
3
3
  import { toolFunctions } from "../tools/index.js";
4
4
  import { agentProfiles, defaultSubAgentTools } from "../config/agentProfiles.js";
5
5
  import { config } from "../config/default.js";
@@ -8,6 +8,7 @@ import { v4 as uuidv4 } from "uuid";
8
8
  import tenantContext from "../tenants/TenantContext.js";
9
9
  import { resolveModelForProfile } from "../models/ModelRouter.js";
10
10
  import { createSession, getSession, setMessages } from "../services/sessions.js";
11
+ import skillLoader from "../skills/SkillLoader.js";
11
12
 
12
13
  /**
13
14
  * Sub-Agent Manager - spawns, tracks, kills, and steers sub-agents.
@@ -29,6 +30,27 @@ import { createSession, getSession, setMessages } from "../services/sessions.js"
29
30
 
30
31
  const MAX_CONCURRENT_SUB_AGENTS = 7;
31
32
 
33
+ /**
34
+ * Resolve sub-agent model. Priority:
35
+ * 1. Profile-specific route (tenant modelRoutes[profile] or CODE_MODEL/etc env)
36
+ * 2. SUB_AGENT_MODEL (tenant-level or env-level)
37
+ * 3. Parent agent's model (inherit from main agent)
38
+ * 4. DEFAULT_MODEL
39
+ */
40
+ function _resolveSubAgentModel(profile, tenantConfig, parentModel) {
41
+ const _profileEnvMap = { coder: "CODE_MODEL", researcher: "RESEARCH_MODEL", writer: "WRITER_MODEL", analyst: "ANALYST_MODEL" };
42
+ // 1. Profile-specific
43
+ if (profile && tenantConfig.modelRoutes?.[profile]) return tenantConfig.modelRoutes[profile];
44
+ if (profile && process.env[_profileEnvMap[profile]]) return process.env[_profileEnvMap[profile]];
45
+ // 2. Sub-agent model (tenant > env)
46
+ if (tenantConfig.subAgentModel) return tenantConfig.subAgentModel;
47
+ if (process.env.SUB_AGENT_MODEL) return process.env.SUB_AGENT_MODEL;
48
+ // 3. Parent's model — sub-agents default to the same model as the main agent
49
+ if (parentModel) return parentModel;
50
+ // 4. Global default
51
+ return config.defaultModel;
52
+ }
53
+
32
54
  /** Map<agentId, { taskDescription, startedAt, parentTaskId, abortController, steerQueue }> */
33
55
  const activeSubAgents = new Map();
34
56
 
@@ -83,6 +105,7 @@ eventBus.on("supervisor:kill", ({ taskId }) => {
83
105
  * @param {number} [options.depth] Recursion depth (managed internally)
84
106
  * @param {string} [options.parentTaskId] Parent task ID for kill propagation
85
107
  * @param {string} [options.parentContext] Summary/context from parent agent
108
+ * @param {string[]} [options.skills] Skill paths to inject (e.g. ["skills/coding.md", "skills/brand-guidelines.md"])
86
109
  * @param {string} [options.approvalMode] Inherited approval mode
87
110
  * @param {object} [options.channelMeta] Inherited channel meta for approvals
88
111
  * @returns {Promise<string>} Sub-agent's final response
@@ -100,6 +123,7 @@ export async function spawnSubAgent(taskDescription, options = {}) {
100
123
  depth = 0,
101
124
  parentTaskId = null,
102
125
  parentContext = null,
126
+ skills = null, // explicit skill paths to inject (e.g. ["skills/coding.md"])
103
127
  approvalMode = "auto",
104
128
  channelMeta = null,
105
129
  historyMessages = [], // previous session messages to prepend (persistent sub-agent sessions)
@@ -118,12 +142,12 @@ export async function spawnSubAgent(taskDescription, options = {}) {
118
142
  const agentId = uuidv4().slice(0, 8);
119
143
  const taskId = `subagent-${agentId}`;
120
144
 
121
- // ── Model resolution - priority: explicit > profile routing > parent > global default ───────
145
+ // ── Model resolution ────────────────────────────────────────────────────
146
+ // Priority: explicit > profile route > SUB_AGENT_MODEL > parent's model > DEFAULT_MODEL
122
147
  const store = tenantContext.getStore();
148
+ const parentModel = store?.resolvedModel || null;
123
149
  const resolvedModel = model
124
- || resolveModelForProfile(profile, store?.resolvedConfig || {}, null)
125
- || store?.resolvedModel
126
- || config.defaultModel;
150
+ || _resolveSubAgentModel(profile, store?.resolvedConfig || {}, parentModel);
127
151
 
128
152
  const profileLabel = profile ? ` [${profile}]` : "";
129
153
  const modelLabel = resolvedModel ? ` ${C.dim}(${resolvedModel})${C.reset}` : "";
@@ -249,13 +273,62 @@ export async function spawnSubAgent(taskDescription, options = {}) {
249
273
  }
250
274
  }
251
275
 
252
- // ── Build initial messages (include history + optionally parent context) ──
276
+ // ── Skill injection ─────────────────────────────────────────────────────
277
+ // Priority: 1) Explicit skills passed by parent 2) Semantic embedding search
278
+ // Both produce full skill content so the sub-agent doesn't waste a readFile turn.
279
+ let skillContext = "";
280
+ try {
281
+ const injectedSkills = [];
282
+
283
+ // 1. Explicit skills — parent agent passed skill paths/names directly
284
+ if (skills && skills.length > 0) {
285
+ for (const ref of skills) {
286
+ const skill = skillLoader.getSkill(ref);
287
+ if (skill) {
288
+ injectedSkills.push(skill);
289
+ } else {
290
+ console.log(`[SubAgent:${agentId}] Skill not found: "${ref}"`);
291
+ }
292
+ }
293
+ }
294
+
295
+ // 2. Semantic embedding search — find relevant skills the parent didn't explicitly pass
296
+ if (injectedSkills.length === 0 && taskDescription) {
297
+ const semanticResult = await skillLoader.getSkillPromptsAsync(taskDescription);
298
+ if (semanticResult) {
299
+ // getSkillPromptsAsync returns formatted string with --- Skill: name --- blocks
300
+ skillContext = semanticResult;
301
+ }
302
+ }
303
+
304
+ // Format explicitly-passed skills
305
+ if (injectedSkills.length > 0) {
306
+ skillContext = injectedSkills.map(s =>
307
+ `\n--- Skill: ${s.name} ---\n${s.content}\n--- End Skill ---`
308
+ ).join("\n");
309
+ }
310
+
311
+ if (injectedSkills.length > 0) {
312
+ console.log(`[SubAgent:${agentId}] Injected ${injectedSkills.length} skill(s) (explicit): ${injectedSkills.map(s => s.name).join(", ")}`);
313
+ } else if (skillContext) {
314
+ console.log(`[SubAgent:${agentId}] Injected skills (semantic embedding match)`);
315
+ }
316
+ } catch (e) {
317
+ // Non-blocking — skills are optional
318
+ console.log(`[SubAgent:${agentId}] Skill injection failed (non-blocking): ${e.message}`);
319
+ }
320
+
321
+ // ── Build initial messages (include history + parent context + skills) ──
253
322
  const initialMessages = [...historyMessages];
254
323
 
255
- if (parentContext) {
324
+ const contextParts = [];
325
+ if (parentContext) contextParts.push(`[Context from parent agent]:\n${parentContext}`);
326
+ if (skillContext) contextParts.push(`[Matched Skills — follow these instructions precisely]:\n${skillContext}`);
327
+
328
+ if (contextParts.length > 0) {
256
329
  initialMessages.push({
257
330
  role: "user",
258
- content: `[Context from parent agent]:\n${parentContext}\n\n[Your task]:\n${taskDescription}`,
331
+ content: `${contextParts.join("\n\n")}\n\n[Your task]:\n${taskDescription}`,
259
332
  });
260
333
  } else {
261
334
  initialMessages.push({ role: "user", content: taskDescription });