stellar-agent 0.1.0 → 0.3.0

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.
Files changed (27) hide show
  1. package/README.md +68 -1
  2. package/package.json +12 -3
  3. package/src/core-skills/module-help.csv +2 -0
  4. package/src/core-skills/stellar-help/SKILL.md +5 -0
  5. package/src/core-skills/stellar-lean/SKILL.md +70 -0
  6. package/src/core-skills/stellar-party-mode/SKILL.md +2 -1
  7. package/src/core-skills/stellar-project-context/SKILL.md +152 -0
  8. package/src/stellar-skills/1-analysis/stellar-agent-analyst/customize.toml +5 -0
  9. package/src/stellar-skills/1-analysis/stellar-known-assets/SKILL.md +125 -0
  10. package/src/stellar-skills/4-implementation/stellar-agent-devops/customize.toml +5 -0
  11. package/src/stellar-skills/4-implementation/stellar-doctor/SKILL.md +207 -0
  12. package/src/stellar-skills/5-mentorship/stellar-agent-mentor/SKILL.md +60 -0
  13. package/src/stellar-skills/5-mentorship/stellar-agent-mentor/customize.toml +56 -0
  14. package/src/stellar-skills/5-mentorship/stellar-demo-prep/SKILL.md +139 -0
  15. package/src/stellar-skills/5-mentorship/stellar-idea-scoping/SKILL.md +125 -0
  16. package/src/stellar-skills/5-mentorship/stellar-judging-criteria/SKILL.md +119 -0
  17. package/src/stellar-skills/5-mentorship/stellar-mvp-definition/SKILL.md +124 -0
  18. package/src/stellar-skills/5-mentorship/stellar-pitch-coaching/SKILL.md +150 -0
  19. package/src/stellar-skills/5-mentorship/stellar-submission-prep/SKILL.md +234 -0
  20. package/src/stellar-skills/5-mentorship/stellar-track-recommendation/SKILL.md +97 -0
  21. package/src/stellar-skills/module-help.csv +9 -0
  22. package/src/stellar-skills/module.yaml +7 -0
  23. package/tools/installer/commands/init.js +31 -2
  24. package/tools/installer/commands/mcp.js +38 -0
  25. package/tools/installer/commands/version.js +42 -0
  26. package/tools/installer/stellar-cli.js +1 -1
  27. package/tools/mcp-server/server.js +281 -0
@@ -0,0 +1,97 @@
1
+ ---
2
+ name: stellar-track-recommendation
3
+ description: 'Match a hackathon idea to the right Stellar/Soroban track and surface the judging rubric for that track. Use when the user is undecided between tracks, wants to know which track fits their idea best, or needs to read the rubric before building.'
4
+ ---
5
+
6
+ # Track Recommendation
7
+
8
+ ## Purpose
9
+
10
+ Pick the right hackathon track for the idea. The wrong track punishes the team twice — judges score against criteria the build wasn't optimized for, and the team misses the rubric that would've shaped a better build.
11
+
12
+ ## On Activation
13
+
14
+ Load `{planning_artifacts}/hackathon-brief.md` if it exists. If not, recommend running `IS` (Idea Scoping) first.
15
+
16
+ If a hackathon URL was provided to Pera on greeting, fetch it now and read the official track list and rubrics. Treat the live page as source of truth — overrides anything below.
17
+
18
+ ## Workflow
19
+
20
+ ### Step 1: Identify Candidate Tracks
21
+
22
+ Match the idea against the Stellar hackathon track families:
23
+
24
+ | Track | Best fits | Stellar/Soroban primitive | Judging weight |
25
+ |---|---|---|---|
26
+ | **DeFi** | Lending, AMM, yield, perp/swap, stablecoin mech | Soroban contracts, AMM pools, trustlines | Technical depth · Composability · TVL potential |
27
+ | **Payments** | Cross-border, remittance, micropayments, payroll | Classic Stellar payments, anchors, path payments | UX · Cost per tx · Anchor / SEP integration |
28
+ | **Identity / SEP-10** | KYC, attestation, reputation, gated access | SEP-10 auth, Soroban storage for attestations | Privacy · SEP compliance · Real-world fit |
29
+ | **Gaming / NFT** | On-chain assets, in-game economy, collectibles | Custom assets, Soroban inventory contracts | Player retention · Creative use of Soroban |
30
+ | **RWA / Tokenization** | Real estate, invoices, commodities, carbon | Custom assets + Soroban escrow + oracles | Legal viability · Oracle design · Trust model |
31
+ | **Infra / DevTools** | SDKs, dashboards, oracles, indexers | Anything that helps other devs ship on Stellar | Developer adoption · Reusability |
32
+ | **Open / Other** | Idea doesn't fit above | Anything | Innovation · Demo · Business potential |
33
+
34
+ ### Step 2: Score the Idea Against Each Candidate
35
+
36
+ For each candidate track, produce a 3-line block:
37
+
38
+ ```
39
+ <Track>
40
+ Fit: <high | medium | low> — <one-line reason>
41
+ Win condition: <what would the judges score highly>
42
+ Risk: <what the judges will challenge>
43
+ ```
44
+
45
+ If two tracks score `high`, prefer the one with:
46
+ - Smaller judging field (less competition)
47
+ - Rubric the build naturally aligns to without rework
48
+
49
+ ### Step 3: Recommend
50
+
51
+ Output:
52
+
53
+ ```markdown
54
+ ## Track recommendation
55
+
56
+ **Primary:** <track>
57
+ **Why:** <one sentence — the strongest rubric alignment>
58
+ **Risk to mitigate:** <what to harden before submission>
59
+
60
+ **Secondary (if primary doesn't fit at submission):** <track>
61
+ ```
62
+
63
+ ### Step 4: Pull the Rubric
64
+
65
+ If the hackathon URL is known, extract the official rubric from the page. Otherwise use the generic Stellar judging rubric:
66
+
67
+ | Criterion | Default weight | Notes |
68
+ |---|---|---|
69
+ | Innovation | 25% | "Have we seen this before on Stellar?" |
70
+ | Technical implementation | 25% | Soroban depth, code quality, test coverage |
71
+ | Business / impact | 25% | Who pays, how big, distribution path |
72
+ | Demo quality | 25% | Recording, narration, on-chain proof |
73
+
74
+ Append to `{planning_artifacts}/hackathon-brief.md` as a `## Track + rubric` section.
75
+
76
+ ### Step 5: Confirm
77
+
78
+ Ask the user: *"Locking in `<track>` — proceed?"*
79
+
80
+ If yes, suggest `MV` next.
81
+ If no, present the secondary or ask what's missing.
82
+
83
+ ## Common mistakes
84
+
85
+ - **Picking DeFi by default.** DeFi is the most crowded track at most Stellar hackathons. A "DeFi-lite" idea in Payments or Identity often wins more easily.
86
+ - **Picking a track because the team likes it.** Track choice is about rubric fit, not preference.
87
+ - **Ignoring the official rubric.** Always pull the actual hackathon's rubric over generic priors. Hackathons weight criteria differently.
88
+ - **Multi-track submissions.** Most Stellar hackathons only allow one track. Picking two splits attention.
89
+
90
+ ## Output
91
+
92
+ Updates `{planning_artifacts}/hackathon-brief.md` with the chosen track and the rubric the build must align to.
93
+
94
+ ## Next Steps
95
+
96
+ - `stellar-mvp-definition` (MV) — cut the feature list against the chosen rubric
97
+ - `stellar-judging-criteria` (JC) — when the MVP is locked, map it to the rubric line-by-line
@@ -3,11 +3,13 @@ Stellar,_meta,,,,,,,,,false,https://github.com/tolgazorlu/stellar-agent#readme,
3
3
  Stellar,stellar-analytics,Analytics Setup,AN,Set up dbt blockchain analytics for Stellar network data and tokenomics reporting.,,,1-analysis,,,false,{project_knowledge},dbt models
4
4
  Stellar,stellar-market-research,Market Research,MR,DeFi landscape competitive analysis and Stellar ecosystem research.,,,1-analysis,,,false,{planning_artifacts},research document
5
5
  Stellar,stellar-domain-research,Domain Research,DR,Stellar protocol deep dive — tokenomics regulatory landscape and use case research.,,,1-analysis,,,false,{planning_artifacts},research document
6
+ Stellar,stellar-known-assets,Known Assets Registry,KA,Look up canonical Stellar asset issuer addresses (USDC EURC AQUA yXLM) with provenance and verification commands. Prevents issuer hallucination.,,,1-analysis,,,false,,
6
7
  Stellar,stellar-project-brief,Project Brief,PB,Define the dApp concept goals and target users in a concise brief.,,,2-planning,,,false,{planning_artifacts},project-brief
7
8
  Stellar,stellar-prd,Stellar dApp PRD,PR,Create or update Product Requirements Document for a Stellar application.,,,2-planning,stellar-project-brief,,true,{planning_artifacts},prd
8
9
  Stellar,stellar-epics-stories,Epics and Stories,ES,Break PRD into development epics and user stories with Stellar-specific acceptance criteria.,,,2-planning,stellar-prd,,true,{planning_artifacts},epics-stories
9
10
  Stellar,stellar-architecture-doc,Architecture Document,AD,Create technical architecture document covering on-chain vs off-chain Soroban contract design and Horizon integration.,,,3-architecture,stellar-prd,,true,{planning_artifacts},architecture
10
11
  Stellar,stellar-setup-environment,Setup Environment,SE,Set up local Stellar development environment with Docker quickstart Stellar CLI and SDK.,,,4-implementation,,,true,{project_knowledge},environment-guide
12
+ Stellar,stellar-doctor,Stellar Doctor,SD,Diagnose toolchain network reachability wallet state contract state and project context. Run before any deployment.,,,4-implementation,,,false,,
11
13
  Stellar,stellar-init-contract,Init Contract,IC,Initialize a new Soroban smart contract project with Rust workspace and scaffold.,,,4-implementation,stellar-setup-environment,,false,{implementation_artifacts},contract scaffold
12
14
  Stellar,stellar-write-contract,Write Contract,WC,Implement Soroban contract logic including storage types host functions and error handling.,,,4-implementation,stellar-init-contract,,false,{implementation_artifacts},contract code
13
15
  Stellar,stellar-test-contract,Test Contract,TC,Write and run comprehensive Soroban contract tests using the Rust test harness.,,,4-implementation,stellar-write-contract,,true,{implementation_artifacts},test suite
@@ -22,3 +24,10 @@ Stellar,stellar-nextjs-wallet,Next.js Wallet,NW,Integrate Freighter wallet into
22
24
  Stellar,stellar-nextjs-soroban,Next.js Soroban,NS,Call Soroban contracts from Next.js using Server Components API routes and client-side signing.,,,4-implementation,stellar-nextjs-wallet,,false,{implementation_artifacts},soroban-integration
23
25
  Stellar,stellar-freighter-integration,Freighter Integration,FI,Deep Freighter wallet integration — full API reference connection lifecycle and blob signing.,,,4-implementation,stellar-setup-environment,,false,{implementation_artifacts},freighter-integration
24
26
  Stellar,stellar-sep10-auth,SEP-10 Auth,S10,Implement SEP-10 Web Authentication with JWT for Next.js API routes and protected endpoints.,,,4-implementation,stellar-nextjs-setup,,false,{implementation_artifacts},sep10-auth
27
+ Stellar,stellar-idea-scoping,Idea Scoping,IS,Pressure-test the hackathon idea against the build window and produce a one-page brief with cut list.,,,5-mentorship,,,false,{planning_artifacts},hackathon-brief
28
+ Stellar,stellar-track-recommendation,Track Recommendation,TR,Match the idea to the right Stellar/Soroban hackathon track and pull the judging rubric.,,,5-mentorship,stellar-idea-scoping,,false,{planning_artifacts},track-decision
29
+ Stellar,stellar-mvp-definition,MVP Definition,MV,Split features into must-have / nice-to-have / skip with hour estimates and a 25% buffer rule.,,,5-mentorship,stellar-idea-scoping,,false,{planning_artifacts},mvp-cut
30
+ Stellar,stellar-judging-criteria,Judging Criteria,JC,Reverse-map the build to the judging rubric and identify gaps before they cost points.,,,5-mentorship,stellar-mvp-definition,,false,{planning_artifacts},rubric-alignment
31
+ Stellar,stellar-demo-prep,Demo Prep,DM,Build the hackathon demo storyboard 2-3 min script and recording checklist with common failure modes.,,,5-mentorship,stellar-mvp-definition,,false,{implementation_artifacts},demo-storyboard
32
+ Stellar,stellar-pitch-coaching,Pitch Coaching,PC,Build the hackathon pitch 3-minute deck outline elevator pitch and judge Q&A drill.,,,5-mentorship,stellar-demo-prep,,false,{planning_artifacts},pitch-script
33
+ Stellar,stellar-submission-prep,Submission Prep,SP,Final pre-submission checklist repo polish README demo video deployed testnet contract IDs and submission form.,,,5-mentorship,stellar-pitch-coaching,,false,{planning_artifacts},submission-confirmation
@@ -101,3 +101,10 @@ agents:
101
101
  icon: "🎨"
102
102
  team: stellar-development
103
103
  description: "Builds Next.js App Router dApps connected to the Stellar network. Expert in Freighter wallet integration, Soroban contract calls from React, Horizon data fetching in Server Components, and SEP-10 authentication. Knows exactly when to use Server vs Client Components and never exposes private keys."
104
+
105
+ - code: stellar-agent-mentor
106
+ name: Pera
107
+ title: Hackathon Mentor
108
+ icon: "🧭"
109
+ team: stellar-development
110
+ description: "Hackathon-arc mentor who guides teams from idea to demo. Scopes ideas to fit hackathon timeboxes, picks the right Stellar/Soroban track, aligns the build to judging criteria, and coaches demo + pitch. Speaks in checklists and time-boxed cuts — every recommendation tied to the submission deadline."
@@ -54,6 +54,7 @@ async function installStellarAgent(targetDir, config) {
54
54
  planning_artifacts: `${OUTPUT_DIR}/planning-artifacts`,
55
55
  implementation_artifacts: `${OUTPUT_DIR}/implementation-artifacts`,
56
56
  project_knowledge: 'docs',
57
+ skills_version: config.skills_version,
57
58
  };
58
59
  await fsp.writeFile(
59
60
  path.join(stellarDir, 'stellar', 'config.yaml'),
@@ -64,6 +65,7 @@ async function installStellarAgent(targetDir, config) {
64
65
  // Write manifest
65
66
  const manifest = {
66
67
  version: require('../../../package.json').version,
68
+ skills_version: config.skills_version,
67
69
  installed_at: new Date().toISOString(),
68
70
  project_name: config.project_name,
69
71
  };
@@ -209,6 +211,15 @@ icon = "🎨"
209
211
  team = "stellar-development"
210
212
  module = "stellar"
211
213
  description = "Builds Next.js App Router dApps connected to Stellar — Freighter wallet, Soroban contract calls, SEP-10 auth."
214
+
215
+ [[agents]]
216
+ code = "stellar-agent-mentor"
217
+ name = "Pera"
218
+ title = "Hackathon Mentor"
219
+ icon = "🧭"
220
+ team = "stellar-development"
221
+ module = "stellar"
222
+ description = "Hackathon mentor — scopes ideas to the timebox, picks the track, aligns to judging criteria, coaches demo and pitch."
212
223
  `;
213
224
 
214
225
  await fsp.writeFile(path.join(stellarDir, 'config.toml'), tomlContent, 'utf8');
@@ -217,8 +228,23 @@ description = "Builds Next.js App Router dApps connected to Stellar — Freighte
217
228
  }
218
229
 
219
230
  async function action(options) {
231
+ const pkgVersion = require('../../../package.json').version;
232
+ const requestedVersion = options?.skills || pkgVersion;
233
+
234
+ // Pinning warning — we don't ship multi-version download support yet
235
+ if (requestedVersion !== pkgVersion) {
236
+ console.error(
237
+ `⚠️ Skills version mismatch.\n` +
238
+ ` You requested: ${requestedVersion}\n` +
239
+ ` This package: ${pkgVersion}\n\n` +
240
+ ` To pin to a different version, run:\n` +
241
+ ` npx stellar-agent@${requestedVersion} init\n\n` +
242
+ ` Continuing with ${pkgVersion}...\n`
243
+ );
244
+ }
245
+
220
246
  await CLIUtils.displayLogo();
221
- await prompts.intro('Stellar Agent — AI agent team for Stellar blockchain development');
247
+ await prompts.intro(`Stellar Agent v${pkgVersion} — AI agent team for Stellar blockchain development`);
222
248
 
223
249
  // Directory selection
224
250
  const rawDir = await prompts.text({
@@ -298,6 +324,7 @@ async function action(options) {
298
324
  network_preference: networkPreference,
299
325
  primary_language: primaryLanguage,
300
326
  communication_language: communicationLanguage,
327
+ skills_version: pkgVersion,
301
328
  };
302
329
 
303
330
  // Install
@@ -330,6 +357,8 @@ async function action(options) {
330
357
  module.exports = {
331
358
  command: 'init',
332
359
  description: 'Initialize Stellar Agent in your project',
333
- options: [],
360
+ options: [
361
+ ['--skills <version>', 'Pin to a specific skills version (defaults to the installed package version)'],
362
+ ],
334
363
  action,
335
364
  };
@@ -0,0 +1,38 @@
1
+ /**
2
+ * `stellar-agent mcp` — start the MCP server over stdio.
3
+ *
4
+ * Invoked by MCP-aware clients (Claude Desktop, Cline, Continue, Zed)
5
+ * via their server config:
6
+ *
7
+ * {
8
+ * "mcpServers": {
9
+ * "stellar-agent": {
10
+ * "command": "npx",
11
+ * "args": ["stellar-agent", "mcp"]
12
+ * }
13
+ * }
14
+ * }
15
+ */
16
+
17
+ const path = require('node:path');
18
+ const { spawn } = require('node:child_process');
19
+
20
+ async function action() {
21
+ const serverPath = path.join(__dirname, '..', '..', 'mcp-server', 'server.js');
22
+ const child = spawn(process.execPath, [serverPath], {
23
+ stdio: 'inherit',
24
+ });
25
+
26
+ child.on('exit', (code) => process.exit(code ?? 0));
27
+ child.on('error', (err) => {
28
+ console.error('Failed to start MCP server:', err);
29
+ process.exit(1);
30
+ });
31
+ }
32
+
33
+ module.exports = {
34
+ command: 'mcp',
35
+ description: 'Run the Stellar Agent MCP server (stdio). Used by Claude Desktop, Cline, Continue, Zed.',
36
+ options: [],
37
+ action,
38
+ };
@@ -0,0 +1,42 @@
1
+ /**
2
+ * `stellar-agent version` — print CLI version + installed skills version (if any).
3
+ *
4
+ * Outputs both:
5
+ * - the version of this CLI / npm package
6
+ * - the skills version recorded at `_stellar/_config/manifest.yaml`
7
+ * if the current directory has stellar-agent installed
8
+ */
9
+
10
+ const fs = require('node:fs');
11
+ const path = require('node:path');
12
+ const yaml = require('yaml');
13
+
14
+ async function action() {
15
+ const pkg = require('../../../package.json');
16
+ console.log(`stellar-agent v${pkg.version}`);
17
+
18
+ const manifestPath = path.join(process.cwd(), '_stellar', '_config', 'manifest.yaml');
19
+ if (fs.existsSync(manifestPath)) {
20
+ try {
21
+ const manifest = yaml.parse(fs.readFileSync(manifestPath, 'utf8'));
22
+ console.log(` installed: ${manifest.installed_at}`);
23
+ console.log(` skills version: ${manifest.skills_version || manifest.version || '(unknown)'}`);
24
+ console.log(` project: ${manifest.project_name || '(unset)'}`);
25
+ if (manifest.skills_version && manifest.skills_version !== pkg.version) {
26
+ console.log('');
27
+ console.log(` ⚠️ CLI (${pkg.version}) differs from installed skills (${manifest.skills_version}).`);
28
+ console.log(` Run \`npx stellar-agent init\` (choose Update) to refresh, or`);
29
+ console.log(` run \`npx stellar-agent@${manifest.skills_version} <command>\` to stay pinned.`);
30
+ }
31
+ } catch (err) {
32
+ console.error(` (could not parse manifest: ${err.message})`);
33
+ }
34
+ }
35
+ }
36
+
37
+ module.exports = {
38
+ command: 'version',
39
+ description: 'Print the CLI version and the installed skills version (if any)',
40
+ options: [],
41
+ action,
42
+ };
@@ -55,7 +55,7 @@ if (process.stdin.isTTY) {
55
55
  }
56
56
 
57
57
  const commandsPath = path.join(__dirname, 'commands');
58
- const ALLOWED_COMMANDS = ['init'];
58
+ const ALLOWED_COMMANDS = ['init', 'mcp', 'version'];
59
59
 
60
60
  const commands = {};
61
61
  for (const name of ALLOWED_COMMANDS) {
@@ -0,0 +1,281 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Stellar Agent — MCP Server
4
+ *
5
+ * Exposes the stellar-agent skill catalog and agent personas to any
6
+ * MCP-compatible client (Claude Desktop, Cline, Continue, Zed, etc.)
7
+ * over stdio.
8
+ *
9
+ * Hand-rolled JSON-RPC 2.0 implementation to avoid an SDK dependency —
10
+ * keeps the published package lean.
11
+ *
12
+ * Tools exposed:
13
+ * - list_agents → roster of all 8 agents
14
+ * - list_skills(phase?, agent?) → catalog of skills
15
+ * - get_skill(name) → SKILL.md content
16
+ * - get_agent(name) → persona block + menu
17
+ *
18
+ * Run: `stellar-agent mcp` or `node tools/mcp-server/server.js`
19
+ */
20
+
21
+ const fsp = require('node:fs/promises');
22
+ const fs = require('node:fs');
23
+ const path = require('node:path');
24
+ const readline = require('node:readline');
25
+ const yaml = require('yaml');
26
+
27
+ const REPO_ROOT = path.join(__dirname, '..', '..');
28
+ const SRC_DIR = path.join(REPO_ROOT, 'src');
29
+ const STELLAR_SKILLS_DIR = path.join(SRC_DIR, 'stellar-skills');
30
+ const CORE_SKILLS_DIR = path.join(SRC_DIR, 'core-skills');
31
+ const PROTOCOL_VERSION = '2024-11-05';
32
+ const SERVER_INFO = { name: 'stellar-agent', version: require('../../package.json').version };
33
+
34
+ // ---------- Catalog loaders ----------
35
+
36
+ async function loadAgents() {
37
+ const moduleYaml = await fsp.readFile(path.join(STELLAR_SKILLS_DIR, 'module.yaml'), 'utf8');
38
+ const data = yaml.parse(moduleYaml);
39
+ return data.agents || [];
40
+ }
41
+
42
+ async function loadSkills({ phase, agent } = {}) {
43
+ const skills = [];
44
+
45
+ // Walk core-skills/*/SKILL.md
46
+ for (const entry of await fsp.readdir(CORE_SKILLS_DIR, { withFileTypes: true })) {
47
+ if (!entry.isDirectory()) continue;
48
+ const skillPath = path.join(CORE_SKILLS_DIR, entry.name, 'SKILL.md');
49
+ if (!fs.existsSync(skillPath)) continue;
50
+ skills.push(await readSkillFrontmatter(skillPath, 'core', entry.name));
51
+ }
52
+
53
+ // Walk stellar-skills/<phase>/<skill>/SKILL.md
54
+ for (const phaseEntry of await fsp.readdir(STELLAR_SKILLS_DIR, { withFileTypes: true })) {
55
+ if (!phaseEntry.isDirectory()) continue;
56
+ const phaseDir = path.join(STELLAR_SKILLS_DIR, phaseEntry.name);
57
+ for (const skillEntry of await fsp.readdir(phaseDir, { withFileTypes: true })) {
58
+ if (!skillEntry.isDirectory()) continue;
59
+ const skillPath = path.join(phaseDir, skillEntry.name, 'SKILL.md');
60
+ if (!fs.existsSync(skillPath)) continue;
61
+ skills.push(await readSkillFrontmatter(skillPath, phaseEntry.name, skillEntry.name));
62
+ }
63
+ }
64
+
65
+ let filtered = skills;
66
+ if (phase) filtered = filtered.filter((s) => s.phase === phase);
67
+ if (agent) filtered = filtered.filter((s) => (s.agent || '').toLowerCase() === agent.toLowerCase());
68
+ return filtered;
69
+ }
70
+
71
+ async function readSkillFrontmatter(filePath, phase, dirname) {
72
+ const raw = await fsp.readFile(filePath, 'utf8');
73
+ const frontmatter = parseFrontmatter(raw);
74
+ // Detect agent-persona skills by naming convention: stellar-agent-*
75
+ const isAgent = dirname.startsWith('stellar-agent-');
76
+ return {
77
+ name: frontmatter.name || dirname,
78
+ description: frontmatter.description || '',
79
+ phase,
80
+ type: isAgent ? 'agent' : 'skill',
81
+ path: path.relative(REPO_ROOT, filePath),
82
+ };
83
+ }
84
+
85
+ function parseFrontmatter(text) {
86
+ const match = text.match(/^---\n([\s\S]*?)\n---/);
87
+ if (!match) return {};
88
+ const out = {};
89
+ for (const line of match[1].split('\n')) {
90
+ const m = line.match(/^([a-zA-Z_]+):\s*['"]?(.*?)['"]?$/);
91
+ if (m) out[m[1]] = m[2];
92
+ }
93
+ return out;
94
+ }
95
+
96
+ async function getSkillContent(name) {
97
+ // Look in core-skills
98
+ const corePath = path.join(CORE_SKILLS_DIR, name, 'SKILL.md');
99
+ if (fs.existsSync(corePath)) return fsp.readFile(corePath, 'utf8');
100
+ // Look in stellar-skills/<phase>/<name>
101
+ for (const phaseEntry of await fsp.readdir(STELLAR_SKILLS_DIR, { withFileTypes: true })) {
102
+ if (!phaseEntry.isDirectory()) continue;
103
+ const candidate = path.join(STELLAR_SKILLS_DIR, phaseEntry.name, name, 'SKILL.md');
104
+ if (fs.existsSync(candidate)) return fsp.readFile(candidate, 'utf8');
105
+ }
106
+ throw new Error(`Skill not found: ${name}`);
107
+ }
108
+
109
+ async function getAgentDetail(name) {
110
+ const agents = await loadAgents();
111
+ const agent = agents.find(
112
+ (a) =>
113
+ a.code === name ||
114
+ a.name?.toLowerCase() === name.toLowerCase() ||
115
+ a.code === `stellar-agent-${name.toLowerCase()}`
116
+ );
117
+ if (!agent) throw new Error(`Agent not found: ${name}`);
118
+
119
+ // Resolve agent's SKILL.md + customize.toml for menu
120
+ let menu = [];
121
+ let persona = null;
122
+ for (const phaseEntry of await fsp.readdir(STELLAR_SKILLS_DIR, { withFileTypes: true })) {
123
+ if (!phaseEntry.isDirectory()) continue;
124
+ const dir = path.join(STELLAR_SKILLS_DIR, phaseEntry.name, agent.code);
125
+ if (!fs.existsSync(dir)) continue;
126
+ const skillPath = path.join(dir, 'SKILL.md');
127
+ const customizePath = path.join(dir, 'customize.toml');
128
+ if (fs.existsSync(skillPath)) persona = await fsp.readFile(skillPath, 'utf8');
129
+ if (fs.existsSync(customizePath)) {
130
+ const tomlText = await fsp.readFile(customizePath, 'utf8');
131
+ menu = parseAgentMenu(tomlText);
132
+ }
133
+ break;
134
+ }
135
+ return { agent, persona, menu };
136
+ }
137
+
138
+ function parseAgentMenu(toml) {
139
+ // Lightweight extractor for [[agent.menu]] blocks
140
+ const blocks = toml.split(/\[\[agent\.menu\]\]/).slice(1);
141
+ return blocks.map((block) => {
142
+ const lines = block.split('\n');
143
+ const entry = {};
144
+ for (const line of lines) {
145
+ const m = line.match(/^\s*(code|description|skill)\s*=\s*"(.*)"\s*$/);
146
+ if (m) entry[m[1]] = m[2];
147
+ }
148
+ return entry;
149
+ });
150
+ }
151
+
152
+ // ---------- MCP protocol ----------
153
+
154
+ const TOOLS = [
155
+ {
156
+ name: 'list_agents',
157
+ description: 'List all Stellar Agent team members with their handle, role, icon, and phase.',
158
+ inputSchema: { type: 'object', properties: {}, additionalProperties: false },
159
+ },
160
+ {
161
+ name: 'list_skills',
162
+ description:
163
+ 'List available skills in the Stellar Agent catalog. Optionally filter by phase (1-analysis, 2-planning, 3-architecture, 4-implementation, 5-mentorship, core).',
164
+ inputSchema: {
165
+ type: 'object',
166
+ properties: {
167
+ phase: {
168
+ type: 'string',
169
+ description: 'Optional phase filter — e.g. "4-implementation" or "core".',
170
+ },
171
+ },
172
+ additionalProperties: false,
173
+ },
174
+ },
175
+ {
176
+ name: 'get_skill',
177
+ description: 'Return the full SKILL.md content for a named skill (e.g. "stellar-write-contract").',
178
+ inputSchema: {
179
+ type: 'object',
180
+ properties: { name: { type: 'string', description: 'Skill name (kebab-case).' } },
181
+ required: ['name'],
182
+ additionalProperties: false,
183
+ },
184
+ },
185
+ {
186
+ name: 'get_agent',
187
+ description:
188
+ 'Return the persona, principles, and skill menu for a specific Stellar Agent (e.g. "sol", "pera").',
189
+ inputSchema: {
190
+ type: 'object',
191
+ properties: {
192
+ name: { type: 'string', description: 'Agent name or handle (e.g. "sol" or "stellar-agent-developer").' },
193
+ },
194
+ required: ['name'],
195
+ additionalProperties: false,
196
+ },
197
+ },
198
+ ];
199
+
200
+ function jsonResponse(id, result) {
201
+ return JSON.stringify({ jsonrpc: '2.0', id, result });
202
+ }
203
+
204
+ function jsonError(id, code, message) {
205
+ return JSON.stringify({ jsonrpc: '2.0', id, error: { code, message } });
206
+ }
207
+
208
+ async function handleRequest(req) {
209
+ const { id, method, params } = req;
210
+
211
+ if (method === 'initialize') {
212
+ return jsonResponse(id, {
213
+ protocolVersion: PROTOCOL_VERSION,
214
+ capabilities: { tools: {} },
215
+ serverInfo: SERVER_INFO,
216
+ });
217
+ }
218
+
219
+ if (method === 'tools/list') {
220
+ return jsonResponse(id, { tools: TOOLS });
221
+ }
222
+
223
+ if (method === 'tools/call') {
224
+ const { name, arguments: args = {} } = params || {};
225
+ try {
226
+ let payload;
227
+ if (name === 'list_agents') {
228
+ payload = await loadAgents();
229
+ } else if (name === 'list_skills') {
230
+ payload = await loadSkills(args);
231
+ } else if (name === 'get_skill') {
232
+ if (!args.name) throw new Error('Missing required argument: name');
233
+ payload = await getSkillContent(args.name);
234
+ } else if (name === 'get_agent') {
235
+ if (!args.name) throw new Error('Missing required argument: name');
236
+ payload = await getAgentDetail(args.name);
237
+ } else {
238
+ return jsonError(id, -32601, `Unknown tool: ${name}`);
239
+ }
240
+
241
+ const text = typeof payload === 'string' ? payload : JSON.stringify(payload, null, 2);
242
+ return jsonResponse(id, { content: [{ type: 'text', text }] });
243
+ } catch (err) {
244
+ return jsonResponse(id, {
245
+ content: [{ type: 'text', text: `Error: ${err.message}` }],
246
+ isError: true,
247
+ });
248
+ }
249
+ }
250
+
251
+ if (method === 'notifications/initialized') {
252
+ return null; // no response for notifications
253
+ }
254
+
255
+ return jsonError(id, -32601, `Method not found: ${method}`);
256
+ }
257
+
258
+ // ---------- Stdio loop ----------
259
+
260
+ async function main() {
261
+ const rl = readline.createInterface({ input: process.stdin });
262
+ rl.on('line', async (line) => {
263
+ if (!line.trim()) return;
264
+ let req;
265
+ try {
266
+ req = JSON.parse(line);
267
+ } catch (err) {
268
+ process.stdout.write(jsonError(null, -32700, 'Parse error') + '\n');
269
+ return;
270
+ }
271
+ const response = await handleRequest(req);
272
+ if (response) process.stdout.write(response + '\n');
273
+ });
274
+
275
+ rl.on('close', () => process.exit(0));
276
+ }
277
+
278
+ main().catch((err) => {
279
+ console.error('MCP server fatal error:', err);
280
+ process.exit(1);
281
+ });