@inkeep/agents-cli 0.0.0-dev-20250910233151

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.
@@ -0,0 +1,728 @@
1
+ #!/usr/bin/env node
2
+
3
+ // src/commands/create.ts
4
+ import color from "picocolors";
5
+ import * as p from "@clack/prompts";
6
+ import fs from "fs-extra";
7
+ import { exec } from "child_process";
8
+ import { promisify } from "util";
9
+ import path from "path";
10
+ var execAsync = promisify(exec);
11
+ var createAgents = async (args = {}) => {
12
+ let { tenantId, projectId, dirName, openAiKey, anthropicKey, manageApiPort, runApiPort } = args;
13
+ p.intro(color.inverse(" Create Agents Directory "));
14
+ if (!dirName) {
15
+ const dirResponse = await p.text({
16
+ message: "What do you want to name your agents directory?",
17
+ placeholder: "agents",
18
+ defaultValue: "agents",
19
+ validate: (value) => {
20
+ if (!value || value.trim() === "") {
21
+ return "Directory name is required";
22
+ }
23
+ return void 0;
24
+ }
25
+ });
26
+ if (p.isCancel(dirResponse)) {
27
+ p.cancel("Operation cancelled");
28
+ process.exit(0);
29
+ }
30
+ dirName = dirResponse;
31
+ }
32
+ if (!tenantId) {
33
+ const tenantIdResponse = await p.text({
34
+ message: "Enter your tenant ID :",
35
+ placeholder: "(default)",
36
+ defaultValue: "default"
37
+ });
38
+ if (p.isCancel(tenantIdResponse)) {
39
+ p.cancel("Operation cancelled");
40
+ process.exit(0);
41
+ }
42
+ tenantId = tenantIdResponse;
43
+ }
44
+ if (!projectId) {
45
+ const projectIdResponse = await p.text({
46
+ message: "Enter your project ID:",
47
+ placeholder: "(default)",
48
+ defaultValue: "default"
49
+ });
50
+ if (p.isCancel(projectIdResponse)) {
51
+ p.cancel("Operation cancelled");
52
+ process.exit(0);
53
+ }
54
+ projectId = projectIdResponse;
55
+ }
56
+ if (!anthropicKey) {
57
+ const anthropicKeyResponse = await p.text({
58
+ message: "Enter your Anthropic API key (recommended):",
59
+ placeholder: "sk-ant-...",
60
+ defaultValue: ""
61
+ });
62
+ if (p.isCancel(anthropicKeyResponse)) {
63
+ p.cancel("Operation cancelled");
64
+ process.exit(0);
65
+ }
66
+ anthropicKey = anthropicKeyResponse || void 0;
67
+ }
68
+ if (!openAiKey) {
69
+ const openAiKeyResponse = await p.text({
70
+ message: "Enter your OpenAI API key (optional):",
71
+ placeholder: "sk-...",
72
+ defaultValue: ""
73
+ });
74
+ if (p.isCancel(openAiKeyResponse)) {
75
+ p.cancel("Operation cancelled");
76
+ process.exit(0);
77
+ }
78
+ openAiKey = openAiKeyResponse || void 0;
79
+ }
80
+ const s = p.spinner();
81
+ s.start("Creating directory structure...");
82
+ try {
83
+ const directoryPath = path.resolve(process.cwd(), dirName);
84
+ if (await fs.pathExists(directoryPath)) {
85
+ s.stop();
86
+ const overwrite = await p.confirm({
87
+ message: `Directory ${dirName} already exists. Do you want to overwrite it?`
88
+ });
89
+ if (p.isCancel(overwrite) || !overwrite) {
90
+ p.cancel("Operation cancelled");
91
+ process.exit(0);
92
+ }
93
+ s.start("Cleaning existing directory...");
94
+ await fs.emptyDir(directoryPath);
95
+ }
96
+ await fs.ensureDir(directoryPath);
97
+ process.chdir(directoryPath);
98
+ const config = {
99
+ dirName,
100
+ tenantId,
101
+ projectId,
102
+ openAiKey,
103
+ anthropicKey,
104
+ manageApiPort: manageApiPort || "3002",
105
+ runApiPort: runApiPort || "3003"
106
+ };
107
+ s.message("Setting up workspace structure...");
108
+ await createWorkspaceStructure(projectId);
109
+ s.message("Creating package configurations...");
110
+ await setupPackageConfigurations(dirName);
111
+ s.message("Setting up environment files...");
112
+ await createEnvironmentFiles(config);
113
+ s.message("Creating service files...");
114
+ await createServiceFiles(config);
115
+ s.message("Creating documentation...");
116
+ await createDocumentation(config);
117
+ s.message("Setting up Turbo...");
118
+ await createTurboConfig();
119
+ s.message("Installing dependencies (this may take a while)...");
120
+ await installDependencies();
121
+ s.message("Setting up database...");
122
+ await setupDatabase();
123
+ s.stop();
124
+ p.note(
125
+ `${color.green("\u2713")} Project created at: ${color.cyan(directoryPath)}
126
+
127
+ ${color.yellow("Next steps:")}
128
+ cd ${dirName}
129
+ npm run dev (for APIs only)
130
+ npx inkeep dev (for APIs + Management Dashboard)
131
+
132
+ ${color.yellow("Available services:")}
133
+ \u2022 Management API: http://localhost:${manageApiPort || "3002"}
134
+ \u2022 Execution API: http://localhost:${runApiPort || "3003"}
135
+ \u2022 Management Dashboard: Available with 'npx inkeep dev'
136
+
137
+ ${color.yellow("Configuration:")}
138
+ \u2022 Edit .env for environment variables
139
+ \u2022 Edit src/${projectId}/hello.graph.ts for agent definitions
140
+ \u2022 Use 'npx inkeep push' to deploy agents to the platform
141
+ \u2022 Use 'npx inkeep chat' to test your agents locally
142
+ `,
143
+ "Ready to go!"
144
+ );
145
+ } catch (error) {
146
+ s.stop();
147
+ p.cancel(
148
+ `Error creating directory: ${error instanceof Error ? error.message : "Unknown error"}`
149
+ );
150
+ process.exit(1);
151
+ }
152
+ };
153
+ async function createWorkspaceStructure(projectId) {
154
+ await fs.ensureDir(`src/${projectId}`);
155
+ await fs.ensureDir("apps/manage-api/src");
156
+ await fs.ensureDir("apps/run-api/src");
157
+ await fs.ensureDir("apps/shared");
158
+ }
159
+ async function setupPackageConfigurations(dirName) {
160
+ const rootPackageJson = {
161
+ name: dirName,
162
+ version: "0.1.0",
163
+ description: "An Inkeep Agent Framework directory",
164
+ private: true,
165
+ type: "module",
166
+ scripts: {
167
+ dev: "turbo dev",
168
+ "db:push": "drizzle-kit push"
169
+ },
170
+ dependencies: {},
171
+ devDependencies: {
172
+ "@biomejs/biome": "^1.8.0",
173
+ "@inkeep/agents-cli": "^0.1.1",
174
+ "drizzle-kit": "^0.31.4",
175
+ tsx: "^4.19.0",
176
+ turbo: "^2.5.5"
177
+ },
178
+ engines: {
179
+ node: ">=22.x"
180
+ },
181
+ packageManager: "npm@10.0.0",
182
+ workspaces: ["apps/*"]
183
+ };
184
+ await fs.writeJson("package.json", rootPackageJson, { spaces: 2 });
185
+ rootPackageJson.dependencies = {
186
+ "@inkeep/agents-core": "^0.1.0",
187
+ "@inkeep/agents-sdk": "^0.1.0",
188
+ zod: "^4.1.5"
189
+ };
190
+ await fs.writeJson("package.json", rootPackageJson, { spaces: 2 });
191
+ const manageApiPackageJson = {
192
+ name: `@${dirName}/manage-api`,
193
+ version: "0.1.0",
194
+ description: "Management API for agents",
195
+ type: "module",
196
+ scripts: {
197
+ build: "tsc",
198
+ dev: "tsx watch src/index.ts",
199
+ start: "node dist/index.js"
200
+ },
201
+ dependencies: {
202
+ "@inkeep/agents-manage-api": "^0.1.1",
203
+ "@inkeep/agents-core": "^0.1.0",
204
+ "@hono/node-server": "^1.14.3"
205
+ },
206
+ devDependencies: {
207
+ "@types/node": "^20.12.0",
208
+ tsx: "^4.19.0",
209
+ typescript: "^5.4.0"
210
+ },
211
+ engines: {
212
+ node: ">=22.x"
213
+ }
214
+ };
215
+ await fs.writeJson("apps/manage-api/package.json", manageApiPackageJson, { spaces: 2 });
216
+ const runApiPackageJson = {
217
+ name: `@${dirName}/run-api`,
218
+ version: "0.1.0",
219
+ description: "Run API for agents",
220
+ type: "module",
221
+ scripts: {
222
+ dev: "tsx watch src/index.ts",
223
+ start: "node dist/index.js"
224
+ },
225
+ dependencies: {
226
+ "@inkeep/agents-run-api": "^0.1.1",
227
+ "@inkeep/agents-core": "^0.1.0",
228
+ "@hono/node-server": "^1.14.3"
229
+ },
230
+ devDependencies: {
231
+ "@types/node": "^20.12.0",
232
+ tsx: "^4.19.0",
233
+ typescript: "^5.4.0"
234
+ },
235
+ engines: {
236
+ node: ">=22.x"
237
+ }
238
+ };
239
+ await fs.writeJson("apps/run-api/package.json", runApiPackageJson, { spaces: 2 });
240
+ const apiTsConfig = {
241
+ compilerOptions: {
242
+ target: "ES2022",
243
+ module: "ESNext",
244
+ moduleResolution: "bundler",
245
+ strict: true,
246
+ esModuleInterop: true,
247
+ skipLibCheck: true,
248
+ forceConsistentCasingInFileNames: true,
249
+ declaration: true,
250
+ outDir: "./dist",
251
+ rootDir: "..",
252
+ allowImportingTsExtensions: false,
253
+ resolveJsonModule: true,
254
+ isolatedModules: true,
255
+ noEmit: false
256
+ },
257
+ include: ["src/**/*", "../shared/**/*"],
258
+ exclude: ["node_modules", "dist", "**/*.test.ts"]
259
+ };
260
+ await fs.writeJson("apps/manage-api/tsconfig.json", apiTsConfig, { spaces: 2 });
261
+ await fs.writeJson("apps/run-api/tsconfig.json", apiTsConfig, { spaces: 2 });
262
+ }
263
+ async function createEnvironmentFiles(config) {
264
+ const envContent = `# Environment
265
+ ENVIRONMENT=development
266
+
267
+ # Database
268
+ DB_FILE_NAME=file:./local.db
269
+
270
+ # AI Provider Keys
271
+ ANTHROPIC_API_KEY=${config.anthropicKey || "your-anthropic-key-here"}
272
+ OPENAI_API_KEY=${config.openAiKey || "your-openai-key-here"}
273
+
274
+ # Logging
275
+ LOG_LEVEL=debug
276
+
277
+ # Service Ports
278
+ MANAGE_API_PORT=${config.manageApiPort}
279
+ RUN_API_PORT=${config.runApiPort}
280
+
281
+ # UI Configuration (for dashboard)
282
+ NEXT_PUBLIC_INKEEP_AGENTS_MANAGE_API_URL=http://localhost:${config.manageApiPort}
283
+ NEXT_PUBLIC_INKEEP_AGENTS_RUN_API_URL=http://localhost:${config.runApiPort}
284
+ `;
285
+ await fs.writeFile(".env", envContent);
286
+ const envExample = envContent.replace(/=.+$/gm, "=");
287
+ await fs.writeFile(".env.example", envExample);
288
+ const runApiEnvContent = `# Environment
289
+ ENVIRONMENT=development
290
+
291
+ # Database (relative path from API directory)
292
+ DB_FILE_NAME=file:../../local.db
293
+
294
+ # AI Provider Keys
295
+ ANTHROPIC_API_KEY=${config.anthropicKey || "your-anthropic-key-here"}
296
+ OPENAI_API_KEY=${config.openAiKey || "your-openai-key-here"}
297
+ `;
298
+ const manageApiEnvContent = `# Environment
299
+ ENVIRONMENT=development
300
+
301
+ # Database (relative path from API directory)
302
+ DB_FILE_NAME=file:../../local.db
303
+ `;
304
+ await fs.writeFile("apps/manage-api/.env", manageApiEnvContent);
305
+ await fs.writeFile("apps/run-api/.env", runApiEnvContent);
306
+ const gitignore = `# Dependencies
307
+ node_modules/
308
+ .pnpm-store/
309
+
310
+ # Environment variables
311
+ .env
312
+ .env.local
313
+ .env.development.local
314
+ .env.test.local
315
+ .env.production.local
316
+
317
+ # Build outputs
318
+ dist/
319
+ build/
320
+ .next/
321
+ .turbo/
322
+
323
+ # Logs
324
+ *.log
325
+ logs/
326
+
327
+ # Database
328
+ *.db
329
+ *.sqlite
330
+ *.sqlite3
331
+
332
+ # IDE
333
+ .vscode/
334
+ .idea/
335
+ *.swp
336
+ *.swo
337
+
338
+ # OS
339
+ .DS_Store
340
+ Thumbs.db
341
+
342
+ # Coverage
343
+ coverage/
344
+ .nyc_output/
345
+
346
+ # Temporary files
347
+ *.tmp
348
+ *.temp
349
+ .cache/
350
+
351
+ # Runtime data
352
+ pids/
353
+ *.pid
354
+ *.seed
355
+ *.pid.lock
356
+ `;
357
+ await fs.writeFile(".gitignore", gitignore);
358
+ const biomeConfig = {
359
+ linter: {
360
+ enabled: true,
361
+ rules: {
362
+ recommended: true
363
+ }
364
+ },
365
+ formatter: {
366
+ enabled: true,
367
+ indentStyle: "space",
368
+ indentWidth: 2
369
+ },
370
+ organizeImports: {
371
+ enabled: true
372
+ },
373
+ javascript: {
374
+ formatter: {
375
+ semicolons: "always",
376
+ quoteStyle: "single"
377
+ }
378
+ }
379
+ };
380
+ await fs.writeJson("biome.json", biomeConfig, { spaces: 2 });
381
+ }
382
+ async function createServiceFiles(config) {
383
+ const agentsGraph = `import { agent, agentGraph } from '@inkeep/agents-sdk';
384
+
385
+ // Router agent - the entry point that routes users to specialist agents
386
+ const helloAgent = agent({
387
+ id: 'hello',
388
+ name: 'Hello Agent',
389
+ description: 'A hello agent that just says hello.',
390
+ prompt: \`You are a hello agent that just says hello. You only reply with the word "hello", but you may do it in different variations like h3110, h3110w0rld, h3110w0rld! etc...\`,
391
+ });
392
+
393
+
394
+ // Create the agent graph
395
+ export const graph = agentGraph({
396
+ id: 'hello',
397
+ name: 'Hello Graph',
398
+ description: 'A graph that contains the hello agent.',
399
+ defaultAgent: helloAgent,
400
+ agents: () => [helloAgent],
401
+ });`;
402
+ await fs.writeFile(`src/${config.projectId}/hello.graph.ts`, agentsGraph);
403
+ const inkeepConfig = `import { defineConfig } from '@inkeep/agents-cli/config';
404
+
405
+ const config = defineConfig({
406
+ tenantId: "${config.tenantId}",
407
+ projectId: "${config.projectId}",
408
+ agentsManageApiUrl: \`http://localhost:\${process.env.MANAGE_API_PORT || '3002'}\`,
409
+ agentsRunApiUrl: \`http://localhost:\${process.env.RUN_API_PORT || '3003'}\`,
410
+ });
411
+
412
+ export default config;`;
413
+ await fs.writeFile(`src/${config.projectId}/inkeep.config.ts`, inkeepConfig);
414
+ const projectEnvContent = `# Environment
415
+ ENVIRONMENT=development
416
+
417
+ # Database (relative path from project directory)
418
+ DB_FILE_NAME=file:../../local.db
419
+
420
+ # UI Configuration (for dashboard)
421
+ NEXT_PUBLIC_INKEEP_AGENTS_MANAGE_API_URL=http://localhost:${config.manageApiPort}
422
+ NEXT_PUBLIC_INKEEP_AGENTS_RUN_API_URL=http://localhost:${config.runApiPort}
423
+
424
+ `;
425
+ await fs.writeFile(`src/${config.projectId}/.env`, projectEnvContent);
426
+ const credentialStoresFile = `import {
427
+ InMemoryCredentialStore,
428
+ createNangoCredentialStore,
429
+ createKeyChainStore,
430
+ } from '@inkeep/agents-core';
431
+
432
+ // Shared credential stores configuration for all services
433
+ export const credentialStores = [
434
+ new InMemoryCredentialStore('memory-default'),
435
+ ...(process.env.NANGO_SECRET_KEY
436
+ ? [
437
+ createNangoCredentialStore('nango-default', {
438
+ apiUrl: process.env.NANGO_HOST || 'https://api.nango.dev',
439
+ secretKey: process.env.NANGO_SECRET_KEY,
440
+ }),
441
+ ]
442
+ : []),
443
+ createKeyChainStore('keychain-default'),
444
+ ];
445
+ `;
446
+ await fs.writeFile("apps/shared/credential-stores.ts", credentialStoresFile);
447
+ const manageApiIndex = `import { serve } from '@hono/node-server';
448
+ import { createManagementApp } from '@inkeep/agents-manage-api';
449
+ import { getLogger } from '@inkeep/agents-core';
450
+ import { credentialStores } from '../../shared/credential-stores.js';
451
+
452
+ const logger = getLogger('management-api');
453
+
454
+ // Create the Hono app
455
+ const app = createManagementApp({
456
+ serverConfig: {
457
+ port: Number(process.env.MANAGE_API_PORT) || 3002,
458
+ serverOptions: {
459
+ requestTimeout: 60000,
460
+ keepAliveTimeout: 60000,
461
+ keepAlive: true,
462
+ },
463
+ },
464
+ credentialStores,
465
+ });
466
+
467
+ const port = Number(process.env.MANAGE_API_PORT) || 3002;
468
+
469
+ // Start the server using @hono/node-server
470
+ serve(
471
+ {
472
+ fetch: app.fetch,
473
+ port,
474
+ },
475
+ (info) => {
476
+ logger.info({}, \`\u{1F4DD} Management API running on http://localhost:\${info.port}\`);
477
+ logger.info({}, \`\u{1F4DD} OpenAPI documentation available at http://localhost:\${info.port}/openapi.json\`);
478
+ }
479
+ );`;
480
+ await fs.writeFile("apps/manage-api/src/index.ts", manageApiIndex);
481
+ const runApiIndex = `import { serve } from '@hono/node-server';
482
+ import { createExecutionApp } from '@inkeep/agents-run-api';
483
+ import { credentialStores } from '../../shared/credential-stores.js';
484
+ import { getLogger } from '@inkeep/agents-core';
485
+
486
+ const logger = getLogger('execution-api');
487
+
488
+
489
+ // Create the Hono app
490
+ const app = createExecutionApp({
491
+ serverConfig: {
492
+ port: Number(process.env.RUN_API_PORT) || 3003,
493
+ serverOptions: {
494
+ requestTimeout: 120000,
495
+ keepAliveTimeout: 60000,
496
+ keepAlive: true,
497
+ },
498
+ },
499
+ credentialStores,
500
+ });
501
+
502
+ const port = Number(process.env.RUN_API_PORT) || 3003;
503
+
504
+ // Start the server using @hono/node-server
505
+ serve(
506
+ {
507
+ fetch: app.fetch,
508
+ port,
509
+ },
510
+ (info) => {
511
+ logger.info({}, \`\u{1F4DD} Execution API running on http://localhost:\${info.port}\`);
512
+ logger.info({}, \`\u{1F4DD} OpenAPI documentation available at http://localhost:\${info.port}/openapi.json\`);
513
+ }
514
+ );`;
515
+ await fs.writeFile("apps/run-api/src/index.ts", runApiIndex);
516
+ const drizzleConfig = `import { defineConfig } from 'drizzle-kit';
517
+
518
+ export default defineConfig({
519
+ schema: 'node_modules/@inkeep/agents-core/dist/db/schema.js',
520
+ dialect: 'sqlite',
521
+ dbCredentials: {
522
+ url: process.env.DB_FILE_NAME || 'file:./local.db'
523
+ },
524
+ });`;
525
+ await fs.writeFile("drizzle.config.ts", drizzleConfig);
526
+ }
527
+ async function createTurboConfig() {
528
+ const turboConfig = {
529
+ $schema: "https://turbo.build/schema.json",
530
+ ui: "tui",
531
+ globalDependencies: ["**/.env", "**/.env.local", "**/.env.*"],
532
+ globalEnv: [
533
+ "NODE_ENV",
534
+ "CI",
535
+ "ANTHROPIC_API_KEY",
536
+ "OPENAI_API_KEY",
537
+ "ENVIRONMENT",
538
+ "DB_FILE_NAME",
539
+ "MANAGE_API_PORT",
540
+ "RUN_API_PORT",
541
+ "LOG_LEVEL",
542
+ "NANGO_SECRET_KEY"
543
+ ],
544
+ tasks: {
545
+ build: {
546
+ dependsOn: ["^build"],
547
+ inputs: ["$TURBO_DEFAULT$", ".env*"],
548
+ outputs: ["dist/**", "build/**", ".next/**", "!.next/cache/**"]
549
+ },
550
+ dev: {
551
+ cache: false,
552
+ persistent: true
553
+ },
554
+ start: {
555
+ dependsOn: ["build"],
556
+ cache: false
557
+ },
558
+ "db:push": {
559
+ cache: false,
560
+ inputs: ["drizzle.config.ts", "src/data/db/schema.ts"]
561
+ }
562
+ }
563
+ };
564
+ await fs.writeJson("turbo.json", turboConfig, { spaces: 2 });
565
+ }
566
+ async function createDocumentation(config) {
567
+ const readme = `# ${config.dirName}
568
+
569
+ An Inkeep Agent Framework project with multi-service architecture.
570
+
571
+ ## Architecture
572
+
573
+ This project follows a workspace structure with the following services:
574
+
575
+ - **Agents Management API** (Port 3002): Agent configuration and managemen
576
+ - Handles entity management and configuration endpoints.
577
+ - **Agents Run API** (Port 3003): Agent execution and chat processing
578
+ - Handles agent communication. You can interact with your agents either over MCP from an MCP client or through our React UI components library
579
+ - **Management Dashboard** (Port 3000): Web interface available via \`npx inkeep dev\`
580
+ - The agent framework visual builder. From the builder you can create, manage and visualize all your graphs.
581
+
582
+ ## Quick Start
583
+
584
+ 1. **Start services:**
585
+ \`\`\`bash
586
+ # Start Agents Management API and Agents Run API
587
+ npm run dev
588
+
589
+ # Start Dashboard
590
+ npx inkeep dev
591
+ \`\`\`
592
+
593
+ 3. **Deploy your first agent graph:**
594
+ \`\`\`bash
595
+ # Navigate to your project's graph directory
596
+ cd src/${config.projectId}/
597
+
598
+ # Push the hello graph to create it
599
+ npx inkeep push hello.graph.ts
600
+ \`\`\`
601
+ - Follow the prompts to create the project and graph
602
+ - Click on the "View graph in UI:" link to see the graph in the management dashboard
603
+
604
+ ## Project Structure
605
+
606
+ \`\`\`
607
+ ${config.dirName}/
608
+ \u251C\u2500\u2500 src/
609
+ \u2502 \u251C\u2500\u2500 /${config.projectId} # Agent configurations
610
+ \u251C\u2500\u2500 apps/
611
+ \u2502 \u251C\u2500\u2500 manage-api/ # Agents Management API service
612
+ \u2502 \u251C\u2500\u2500 run-api/ # Agents Run API service
613
+ \u2502 \u2514\u2500\u2500 shared/ # Shared code between API services
614
+ \u2502 \u2514\u2500\u2500 credential-stores.ts # Shared credential store configuration
615
+ \u251C\u2500\u2500 turbo.json # Turbo configuration
616
+ \u2514\u2500\u2500 package.json # Root package configuration with npm workspaces
617
+ \`\`\`
618
+
619
+ ## Configuration
620
+
621
+ ### Environment Variables
622
+
623
+ Environment variables are defined in the following places:
624
+
625
+ - \`apps/manage-api/.env\`: Agents Management API environment variables
626
+ - \`apps/run-api/.env\`: Agents Run API environment variables
627
+ - \`src/${config.projectId}/.env\`: Inkeep CLI environment variables
628
+ - \`.env\`: Root environment variables
629
+
630
+ To change the API keys used by your agents modify \`apps/run-api/.env\`. You are required to define at least one LLM provider key.
631
+
632
+ \`\`\`bash
633
+ # AI Provider Keys
634
+ ANTHROPIC_API_KEY=your-anthropic-key-here
635
+ OPENAI_API_KEY=your-openai-key-here
636
+ \`\`\`
637
+
638
+ To change the ports used by your services modify \`apps/manage-api/.env\` and \`apps/run-api/.env\` respectively:
639
+
640
+ \`\`\`bash
641
+ # Service port for apps/run-api
642
+ RUN_API_PORT=3003
643
+
644
+ # Service port for apps/manage-api
645
+ MANAGE_API_PORT
646
+ \`\`\`
647
+
648
+ After changing the API Service ports make sure that you modify the dashboard API urls from whichever directory you are running \`npx inkeep dev\`:
649
+
650
+ \`\`\`bash
651
+ # UI Configuration (for dashboard)
652
+ NEXT_PUBLIC_INKEEP_AGENTS_MANAGE_API_URL=http://localhost:${config.manageApiPort}
653
+ NEXT_PUBLIC_INKEEP_AGENTS_RUN_API_URL=http://localhost:${config.runApiPort}
654
+ \`\`\`
655
+
656
+ ### Agent Configuration
657
+
658
+ Your agents are defined in \`src/${config.projectId}/index.ts\`. The default setup includes:
659
+
660
+ - **Hello Agent**: A hello agent that just says hello.
661
+
662
+ Your inkeep configuration is defined in \`src/${config.projectId}/inkeep.config.ts\`. The inkeep configuration is used to configure defaults for the inkeep CLI. The configuration includes:
663
+
664
+ - \`tenantId\`: The tenant ID
665
+ - \`projectId\`: The project ID
666
+ - \`agentsManageApiUrl\`: The management API URL
667
+ - \`agentsRunApiUrl\`: The execution API URL
668
+
669
+
670
+ ## Development
671
+
672
+ ### Updating Your Agents
673
+
674
+ 1. Edit \`src/${config.projectId}/index.ts\`
675
+ 2. Push the graph to the platform to update: \`npx inkeep push hello.graph.ts\`
676
+
677
+ ### API Documentation
678
+
679
+ Once services are running, view the OpenAPI documentation:
680
+
681
+ - Management API: http://localhost:${config.manageApiPort}/docs
682
+ - Execution API: http://localhost:${config.runApiPort}/docs
683
+
684
+ ## Learn More
685
+
686
+ - [Inkeep Documentation](https://docs.inkeep.com)
687
+
688
+ ## Troubleshooting
689
+
690
+ ## Inkeep CLI commands
691
+
692
+ - Ensure you are runnning commands from \`cd src/${config.projectId}\`.
693
+ - Validate the \`inkeep.config.ts\` file has the correct api urls.
694
+ - Validate that the \`.env\` file in \`src/${config.projectId}\` has the correct \`DB_FILE_NAME\`.
695
+
696
+ ### Services won't start
697
+
698
+ 1. Ensure all dependencies are installed: \`npm install\`
699
+ 2. Check that ports 3000-3003 are available
700
+
701
+ ### Agents won't respond
702
+
703
+ 1. Ensure that the Agents Run API is running and includes a valid Anthropic or OpenAI API key in its .env file
704
+ `;
705
+ await fs.writeFile("README.md", readme);
706
+ }
707
+ async function installDependencies() {
708
+ await execAsync("npm install");
709
+ }
710
+ async function setupDatabase() {
711
+ try {
712
+ await execAsync("npx drizzle-kit push");
713
+ } catch (error) {
714
+ throw new Error(
715
+ `Failed to setup database: ${error instanceof Error ? error.message : "Unknown error"}`
716
+ );
717
+ }
718
+ }
719
+ async function createCommand(dirName, options) {
720
+ await createAgents({
721
+ dirName,
722
+ ...options
723
+ });
724
+ }
725
+ export {
726
+ createAgents,
727
+ createCommand
728
+ };