@aman_asmuei/aman 0.1.1 → 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.
package/Dockerfile ADDED
@@ -0,0 +1,47 @@
1
+ # aman ecosystem — full AI companion in one container
2
+ # Includes: aman-agent (CLI) + achannel (Telegram/Discord/webhook) + aman-mcp + amem
3
+ #
4
+ # Build: docker build -t aman .
5
+ # Run: docker run -it -e ANTHROPIC_API_KEY=sk-... aman
6
+ # Serve: docker run -d -p 3000:3000 -e ANTHROPIC_API_KEY=sk-... aman serve
7
+
8
+ FROM node:22-alpine AS base
9
+
10
+ # Install system dependencies
11
+ RUN apk add --no-cache git curl
12
+
13
+ WORKDIR /app
14
+
15
+ # Install all ecosystem packages globally
16
+ RUN npm install -g \
17
+ @aman_asmuei/aman-agent@latest \
18
+ @aman_asmuei/aman-mcp@latest \
19
+ @aman_asmuei/achannel@latest \
20
+ @aman_asmuei/aman@latest
21
+
22
+ # Create ecosystem directories
23
+ RUN mkdir -p /root/.acore /root/.amem /root/.akit /root/.aflow \
24
+ /root/.arules /root/.aeval /root/.askill /root/.aman-agent
25
+
26
+ # Default environment
27
+ ENV NODE_ENV=production
28
+ ENV AMEM_DB_PATH=/root/.amem/memory.db
29
+
30
+ # Volumes for persistent data
31
+ VOLUME ["/root/.acore", "/root/.amem", "/root/.aman-agent"]
32
+
33
+ # Expose webhook port (achannel serve)
34
+ EXPOSE 3000
35
+
36
+ # Healthcheck for server mode
37
+ HEALTHCHECK --interval=30s --timeout=5s --retries=3 \
38
+ CMD curl -f http://localhost:3000/status || exit 1
39
+
40
+ # Entrypoint script
41
+ COPY docker-entrypoint.sh /usr/local/bin/
42
+ RUN chmod +x /usr/local/bin/docker-entrypoint.sh
43
+
44
+ ENTRYPOINT ["docker-entrypoint.sh"]
45
+
46
+ # Default: interactive CLI mode
47
+ CMD ["agent"]
@@ -0,0 +1,29 @@
1
+ [Unit]
2
+ Description=aman AI companion server
3
+ After=network.target
4
+ Wants=network-online.target
5
+
6
+ [Service]
7
+ Type=simple
8
+ User=aman
9
+ WorkingDirectory=/home/aman
10
+ ExecStart=/usr/bin/npx @aman_asmuei/achannel serve
11
+ Restart=always
12
+ RestartSec=10
13
+
14
+ # Environment — set your API key
15
+ EnvironmentFile=/home/aman/.aman-agent/env
16
+
17
+ # Logging
18
+ StandardOutput=journal
19
+ StandardError=journal
20
+ SyslogIdentifier=aman
21
+
22
+ # Security hardening
23
+ NoNewPrivileges=true
24
+ ProtectSystem=strict
25
+ ProtectHome=read-only
26
+ ReadWritePaths=/home/aman/.acore /home/aman/.amem /home/aman/.aman-agent /home/aman/.aeval /home/aman/.arules /home/aman/.aflow /home/aman/.akit /home/aman/.askill
27
+
28
+ [Install]
29
+ WantedBy=multi-user.target
package/dist/index.js CHANGED
@@ -32,8 +32,8 @@ function detectPlatform(cwd) {
32
32
  const raw = fs.readFileSync(configPath, "utf-8");
33
33
  const parsed = JSON.parse(raw);
34
34
  if (typeof parsed.platform === "string") {
35
- const p3 = parsed.platform;
36
- if (p3 === "claude-code" || p3 === "cursor" || p3 === "windsurf") return p3;
35
+ const p4 = parsed.platform;
36
+ if (p4 === "claude-code" || p4 === "cursor" || p4 === "windsurf") return p4;
37
37
  }
38
38
  } catch {
39
39
  }
@@ -132,13 +132,23 @@ function detectEcosystem() {
132
132
  } catch {
133
133
  }
134
134
  }
135
+ const askillPath = path.join(home, ".askill", "skills.md");
136
+ let askillCount = 0;
137
+ if (fs.existsSync(askillPath)) {
138
+ try {
139
+ const content = fs.readFileSync(askillPath, "utf-8");
140
+ askillCount = (content.match(/^## /gm) || []).length;
141
+ } catch {
142
+ }
143
+ }
135
144
  return {
136
145
  acore: { installed: fs.existsSync(acorePath), path: acorePath },
137
146
  amem: { installed: amemInstalled },
138
147
  akit: { installed: fs.existsSync(akitPath), path: akitPath, toolCount: akitToolCount },
139
148
  aflow: { installed: fs.existsSync(aflowPath), path: aflowPath, workflowCount: aflowWorkflowCount },
140
149
  arules: { installed: fs.existsSync(arulesPath), path: arulesPath, ruleCount: arulesRuleCount },
141
- aeval: { installed: fs.existsSync(aevalPath), path: aevalPath, sessions: aevalSessions }
150
+ aeval: { installed: fs.existsSync(aevalPath), path: aevalPath, sessions: aevalSessions },
151
+ askill: { installed: fs.existsSync(askillPath), path: askillPath, skillCount: askillCount }
142
152
  };
143
153
  }
144
154
 
@@ -246,6 +256,93 @@ function getPlatformFile(platform) {
246
256
  }
247
257
  }
248
258
 
259
+ // src/templates.ts
260
+ var STARTER_FLOW = `# My Workflows
261
+
262
+ ## code-review
263
+ When asked to review code:
264
+ 1. Analyze for bugs, logic errors, and edge cases
265
+ 2. Check for security vulnerabilities (OWASP top 10)
266
+ 3. Evaluate code style and maintainability
267
+ 4. Summarize findings with severity ratings (critical/warning/info)
268
+ 5. Suggest specific fixes with code examples
269
+
270
+ ## bug-fix
271
+ When asked to fix a bug:
272
+ 1. Reproduce \u2014 understand the expected vs actual behavior
273
+ 2. Locate \u2014 find the root cause in the codebase
274
+ 3. Fix \u2014 implement the minimal change that fixes the issue
275
+ 4. Test \u2014 verify the fix works and doesn't break other things
276
+ 5. Document \u2014 explain what was wrong and why the fix works
277
+
278
+ ## feature-build
279
+ When asked to build a feature:
280
+ 1. Clarify \u2014 ask questions until requirements are clear
281
+ 2. Design \u2014 propose an approach, get approval
282
+ 3. Implement \u2014 write the code in small, testable increments
283
+ 4. Test \u2014 write and run tests for the new code
284
+ 5. Review \u2014 check for edge cases, security, and performance
285
+
286
+ ## daily-standup
287
+ When starting a new session:
288
+ 1. Check git log for recent changes
289
+ 2. Review open PRs and issues
290
+ 3. Summarize: what was done, what's in progress, what's blocked
291
+ 4. Ask what to focus on today
292
+ `;
293
+ var STARTER_RULES = `# My AI Rules
294
+
295
+ ## Always
296
+ - Ask before deleting files or data
297
+ - Explain your reasoning before making changes
298
+ - Flag security concerns immediately
299
+ - Respect code review processes
300
+
301
+ ## Never
302
+ - Push directly to main/master without approval
303
+ - Expose secrets, API keys, or credentials in code
304
+ - Make changes to production systems without confirmation
305
+ - Skip tests when fixing bugs
306
+
307
+ ## Coding
308
+ - Follow existing code style and conventions
309
+ - Prefer simple solutions over clever ones
310
+ - Write tests for new functionality
311
+ - Keep PRs focused and small
312
+
313
+ ## Communication
314
+ - Be direct \u2014 lead with the answer
315
+ - Admit when you don't know something
316
+ - Ask clarifying questions before assuming
317
+ - Flag when a task is outside your expertise
318
+
319
+ ## Data
320
+ - Never log or expose personal information
321
+ - Treat user data as confidential
322
+ - Ask before accessing external APIs
323
+ - Don't store credentials in plain text
324
+
325
+ ## Team
326
+ - Follow the team's branching strategy
327
+ - Respect code ownership boundaries
328
+ - Tag relevant people for review
329
+ - Document breaking changes
330
+ `;
331
+ var STARTER_EVAL = `# AI Relationship Metrics
332
+
333
+ ## Overview
334
+ - Sessions: 0
335
+ - First session: {{DATE}}
336
+ - Trust level: 3/5
337
+ - Trajectory: building
338
+
339
+ ## Timeline
340
+
341
+ ## Milestones
342
+
343
+ ## Patterns
344
+ `;
345
+
249
346
  // src/commands/setup.ts
250
347
  var ARCHETYPES = {
251
348
  pragmatist: {
@@ -366,6 +463,74 @@ async function setupCommand() {
366
463
  if (stack) inferredParts.push(stack);
367
464
  p.log.info(`Inferred: ${pc.dim(inferredParts.join(" \xB7 "))}`);
368
465
  }
466
+ const home = os2.homedir();
467
+ const aflowExists = ecosystem.aflow.installed;
468
+ const arulesExists = ecosystem.arules.installed;
469
+ const aevalExists = ecosystem.aeval.installed;
470
+ if (aflowExists && arulesExists && aevalExists) {
471
+ p.log.success(`Workflows: ${ecosystem.aflow.workflowCount} defined`);
472
+ p.log.success(`Guardrails: ${ecosystem.arules.ruleCount} rules`);
473
+ p.log.success("Evaluation: already configured");
474
+ } else {
475
+ const setupChoice = await p.select({
476
+ message: "Set up additional layers?",
477
+ options: [
478
+ { value: "all", label: "Yes, set up everything", hint: "recommended" },
479
+ { value: "choose", label: "Let me choose" },
480
+ { value: "skip", label: "Skip for now" }
481
+ ],
482
+ initialValue: "all"
483
+ });
484
+ if (p.isCancel(setupChoice)) process.exit(0);
485
+ let doFlow = false;
486
+ let doRules = false;
487
+ let doEval = false;
488
+ if (setupChoice === "all") {
489
+ doFlow = !aflowExists;
490
+ doRules = !arulesExists;
491
+ doEval = !aevalExists;
492
+ } else if (setupChoice === "choose") {
493
+ const layers = await p.multiselect({
494
+ message: "Which layers?",
495
+ options: [
496
+ ...!aflowExists ? [{ value: "flow", label: "Workflows", hint: "4 starter workflows" }] : [],
497
+ ...!arulesExists ? [{ value: "rules", label: "Guardrails", hint: "24 starter rules" }] : [],
498
+ ...!aevalExists ? [{ value: "eval", label: "Evaluation", hint: "track relationship metrics" }] : []
499
+ ],
500
+ required: false
501
+ });
502
+ if (p.isCancel(layers)) process.exit(0);
503
+ const selected = layers;
504
+ doFlow = selected.includes("flow");
505
+ doRules = selected.includes("rules");
506
+ doEval = selected.includes("eval");
507
+ }
508
+ if (doFlow) {
509
+ const aflowDir = path3.join(home, ".aflow");
510
+ fs4.mkdirSync(aflowDir, { recursive: true });
511
+ fs4.writeFileSync(path3.join(aflowDir, "flow.md"), STARTER_FLOW, "utf-8");
512
+ p.log.success(`Workflows: created ${pc.dim("~/.aflow/flow.md")} (4 starter workflows)`);
513
+ } else if (aflowExists) {
514
+ p.log.success(`Workflows: ${ecosystem.aflow.workflowCount} defined`);
515
+ }
516
+ if (doRules) {
517
+ const arulesDir = path3.join(home, ".arules");
518
+ fs4.mkdirSync(arulesDir, { recursive: true });
519
+ fs4.writeFileSync(path3.join(arulesDir, "rules.md"), STARTER_RULES, "utf-8");
520
+ p.log.success(`Guardrails: created ${pc.dim("~/.arules/rules.md")} (24 rules)`);
521
+ } else if (arulesExists) {
522
+ p.log.success(`Guardrails: ${ecosystem.arules.ruleCount} rules`);
523
+ }
524
+ if (doEval) {
525
+ const aevalDir = path3.join(home, ".aeval");
526
+ fs4.mkdirSync(aevalDir, { recursive: true });
527
+ const today = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
528
+ fs4.writeFileSync(path3.join(aevalDir, "eval.md"), STARTER_EVAL.replace("{{DATE}}", today), "utf-8");
529
+ p.log.success(`Evaluation: created ${pc.dim("~/.aeval/eval.md")}`);
530
+ } else if (aevalExists) {
531
+ p.log.success("Evaluation: already configured");
532
+ }
533
+ }
369
534
  if (ecosystem.amem.installed) {
370
535
  p.log.success("Memory: amem connected");
371
536
  } else {
@@ -376,28 +541,18 @@ async function setupCommand() {
376
541
  p.log.info(`Memory: built-in via core.md (upgrade with ${pc.bold("npx @aman_asmuei/amem")})`);
377
542
  }
378
543
  }
379
- if (ecosystem.akit.installed) {
380
- p.log.success(`Tools: ${ecosystem.akit.toolCount} tools configured`);
381
- } else {
382
- p.log.info(`Tools: run ${pc.bold("npx @aman_asmuei/akit add github")} to add capabilities`);
383
- }
384
- if (ecosystem.aflow.installed) {
385
- p.log.success(`Workflows: ${ecosystem.aflow.workflowCount} defined`);
386
- } else {
387
- p.log.info(`Workflows: run ${pc.bold("npx @aman_asmuei/aflow init")} to add AI workflows`);
388
- }
389
544
  const card = [
390
545
  "",
391
546
  ` ${pc.green("\u2714")} Your AI companion is ready.`,
392
547
  "",
393
548
  ` ${pc.bold("aman status")} See your full ecosystem`,
394
549
  ` ${pc.bold("acore customize")} Change personality`,
395
- ` ${pc.bold("akit add <tool>")} Add tools`,
550
+ ` ${pc.bold("askill add testing")} Install skills`,
396
551
  ` ${pc.bold("npx @aman_asmuei/amem")} Enable automated memory`,
397
552
  ""
398
553
  ];
399
554
  p.note(card.join("\n"), "");
400
- p.outro(pc.dim("Identity + Memory + Tools \u2014 one ecosystem."));
555
+ p.outro(pc.dim("Identity + Workflows + Guardrails + Evaluation \u2014 one ecosystem."));
401
556
  }
402
557
 
403
558
  // src/commands/status.ts
@@ -441,6 +596,11 @@ function statusCommand() {
441
596
  } else {
442
597
  p2.log.warning(`Evaluation: not tracking \u2014 ${pc2.dim("npx @aman_asmuei/aeval init")}`);
443
598
  }
599
+ if (ecosystem.askill.installed) {
600
+ p2.log.success(`Skills: ${ecosystem.askill.skillCount} installed \u2014 ${pc2.dim("askill list for details")}`);
601
+ } else {
602
+ p2.log.warning(`Skills: none \u2014 ${pc2.dim("npx @aman_asmuei/askill add testing")}`);
603
+ }
444
604
  const platformLabels = {
445
605
  "claude-code": "Claude Code",
446
606
  cursor: "Cursor",
@@ -460,16 +620,225 @@ function statusCommand() {
460
620
  if (ecosystem.aflow.installed) score += 1;
461
621
  if (ecosystem.arules.installed) score += 1;
462
622
  if (ecosystem.aeval.installed) score += 1;
463
- const levels = ["Not started", "Getting started", "Growing", "Building", "Strong", "Advanced", "Complete ecosystem"];
464
- const colors = [pc2.red, pc2.red, pc2.yellow, pc2.yellow, pc2.cyan, pc2.cyan, pc2.green];
623
+ if (ecosystem.askill.installed) score += 1;
624
+ const levels = ["Not started", "Getting started", "Growing", "Building", "Expanding", "Strong", "Advanced", "Complete ecosystem"];
625
+ const colors = [pc2.red, pc2.red, pc2.yellow, pc2.yellow, pc2.cyan, pc2.cyan, pc2.cyan, pc2.green];
465
626
  p2.log.message("");
466
- p2.log.info(`Ecosystem: ${colors[score](levels[score])} (${score}/6 layers active)`);
627
+ p2.log.info(`Ecosystem: ${colors[score](levels[score])} (${score}/7 layers active)`);
467
628
  p2.outro("");
468
629
  }
469
630
 
631
+ // src/commands/deploy.ts
632
+ import fs6 from "fs";
633
+ import path4 from "path";
634
+ import * as p3 from "@clack/prompts";
635
+ import pc3 from "picocolors";
636
+ async function deployCommand() {
637
+ p3.intro(pc3.bold("aman deploy") + pc3.dim(" \u2014 deploy your AI companion anywhere"));
638
+ const method = await p3.select({
639
+ message: "How do you want to deploy?",
640
+ options: [
641
+ { value: "docker", label: "Docker Compose", hint: "VPS, home server, Raspberry Pi" },
642
+ { value: "ollama", label: "Docker + Ollama", hint: "fully local, no API key needed" },
643
+ { value: "systemd", label: "Systemd service", hint: "bare metal Linux / Raspberry Pi" },
644
+ { value: "manual", label: "Show me the commands", hint: "I'll do it myself" }
645
+ ]
646
+ });
647
+ if (p3.isCancel(method)) {
648
+ p3.cancel("Cancelled.");
649
+ return;
650
+ }
651
+ const cwd = process.cwd();
652
+ switch (method) {
653
+ case "docker": {
654
+ await deployDocker(cwd);
655
+ break;
656
+ }
657
+ case "ollama": {
658
+ await deployOllama(cwd);
659
+ break;
660
+ }
661
+ case "systemd": {
662
+ deploySystemd();
663
+ break;
664
+ }
665
+ case "manual": {
666
+ deployManual();
667
+ break;
668
+ }
669
+ }
670
+ p3.outro(pc3.green("Done!"));
671
+ }
672
+ async function deployDocker(cwd) {
673
+ const apiKey = await p3.text({
674
+ message: "Your LLM API key (Anthropic or OpenAI):",
675
+ placeholder: "sk-ant-... or sk-...",
676
+ validate: (v) => v.length < 10 ? "API key too short" : void 0
677
+ });
678
+ if (p3.isCancel(apiKey)) return;
679
+ const isAnthropic = apiKey.startsWith("sk-ant");
680
+ const provider = isAnthropic ? "ANTHROPIC_API_KEY" : "OPENAI_API_KEY";
681
+ const envContent = `# aman ecosystem \u2014 deployment config
682
+ ${provider}=${apiKey}
683
+ AMAN_AI_NAME=Aman
684
+ AMAN_MODEL=${isAnthropic ? "claude-sonnet-4-6" : "gpt-4o"}
685
+
686
+ # Optional: Telegram/Discord bots
687
+ # TELEGRAM_BOT_TOKEN=
688
+ # DISCORD_BOT_TOKEN=
689
+ `;
690
+ const envPath = path4.join(cwd, ".env");
691
+ fs6.writeFileSync(envPath, envContent, "utf-8");
692
+ p3.log.success(`Created ${pc3.bold(".env")} with API key`);
693
+ const pkgDir = findPackageDir();
694
+ copyDeployFile(pkgDir, cwd, "Dockerfile");
695
+ copyDeployFile(pkgDir, cwd, "docker-entrypoint.sh");
696
+ copyDeployFile(pkgDir, cwd, "docker-compose.yml");
697
+ try {
698
+ fs6.chmodSync(path4.join(cwd, "docker-entrypoint.sh"), 493);
699
+ } catch {
700
+ }
701
+ p3.log.success(`Created ${pc3.bold("Dockerfile")} + ${pc3.bold("docker-compose.yml")}`);
702
+ p3.note(
703
+ `${pc3.bold("Start your companion:")}
704
+
705
+ docker compose up -d
706
+
707
+ ${pc3.bold("Access:")}
708
+ Webhook API: http://localhost:3000/chat
709
+ Health check: http://localhost:3000/status
710
+
711
+ ${pc3.bold("Interactive CLI:")}
712
+ docker compose run --rm aman-server agent
713
+
714
+ ${pc3.bold("View logs:")}
715
+ docker compose logs -f`,
716
+ "Next steps"
717
+ );
718
+ }
719
+ async function deployOllama(cwd) {
720
+ const model = await p3.text({
721
+ message: "Ollama model to use:",
722
+ placeholder: "llama3.2",
723
+ initialValue: "llama3.2"
724
+ });
725
+ if (p3.isCancel(model)) return;
726
+ const envContent = `# aman ecosystem \u2014 local deployment (no API key needed)
727
+ AMAN_AI_NAME=Aman
728
+ AMAN_MODEL=${model}
729
+
730
+ # Optional: Telegram/Discord bots
731
+ # TELEGRAM_BOT_TOKEN=
732
+ # DISCORD_BOT_TOKEN=
733
+ `;
734
+ const envPath = path4.join(cwd, ".env");
735
+ fs6.writeFileSync(envPath, envContent, "utf-8");
736
+ p3.log.success(`Created ${pc3.bold(".env")} with Ollama config`);
737
+ const pkgDir = findPackageDir();
738
+ copyDeployFile(pkgDir, cwd, "Dockerfile");
739
+ copyDeployFile(pkgDir, cwd, "docker-entrypoint.sh");
740
+ copyDeployFile(pkgDir, cwd, "docker-compose.ollama.yml");
741
+ const src = path4.join(cwd, "docker-compose.ollama.yml");
742
+ const dest = path4.join(cwd, "docker-compose.yml");
743
+ if (fs6.existsSync(src) && !fs6.existsSync(dest)) {
744
+ fs6.renameSync(src, dest);
745
+ }
746
+ try {
747
+ fs6.chmodSync(path4.join(cwd, "docker-entrypoint.sh"), 493);
748
+ } catch {
749
+ }
750
+ p3.log.success(`Created ${pc3.bold("Dockerfile")} + ${pc3.bold("docker-compose.yml")} (with Ollama)`);
751
+ p3.note(
752
+ `${pc3.bold("Start your companion (fully local):")}
753
+
754
+ docker compose up -d
755
+
756
+ First run downloads ${model} (~2GB). After that it's instant.
757
+
758
+ ${pc3.bold("Access:")}
759
+ Webhook API: http://localhost:3000/chat
760
+ Ollama: http://localhost:11434
761
+
762
+ ${pc3.bold("Works on:")}
763
+ Raspberry Pi 4/5 (ARM64), any Linux, macOS, Windows`,
764
+ "Next steps"
765
+ );
766
+ }
767
+ function deploySystemd() {
768
+ p3.note(
769
+ `${pc3.bold("1. Install Node.js 20+:")}
770
+ curl -fsSL https://deb.nodesource.com/setup_22.x | sudo bash -
771
+ sudo apt install -y nodejs
772
+
773
+ ${pc3.bold("2. Create aman user:")}
774
+ sudo useradd -m -s /bin/bash aman
775
+ sudo -u aman npm install -g @aman_asmuei/achannel @aman_asmuei/aman-mcp
776
+
777
+ ${pc3.bold("3. Configure API key:")}
778
+ sudo mkdir -p /home/aman/.aman-agent
779
+ echo 'ANTHROPIC_API_KEY=sk-ant-...' | sudo tee /home/aman/.aman-agent/env
780
+
781
+ ${pc3.bold("4. Install service:")}
782
+ sudo cp aman.service /etc/systemd/system/
783
+ sudo systemctl daemon-reload
784
+ sudo systemctl enable --now aman
785
+
786
+ ${pc3.bold("5. Check status:")}
787
+ sudo systemctl status aman
788
+ sudo journalctl -u aman -f`,
789
+ "Systemd deployment (Raspberry Pi / bare metal)"
790
+ );
791
+ }
792
+ function deployManual() {
793
+ p3.note(
794
+ `${pc3.bold("Docker (one command):")}
795
+ docker run -d -p 3000:3000 \\
796
+ -e ANTHROPIC_API_KEY=sk-ant-... \\
797
+ -v aman-data:/root/.acore \\
798
+ -v aman-memory:/root/.amem \\
799
+ ghcr.io/amanasmuei/aman serve
800
+
801
+ ${pc3.bold("Docker + Ollama (fully local):")}
802
+ docker run -d --name ollama ollama/ollama
803
+ docker exec ollama ollama pull llama3.2
804
+ docker run -d -p 3000:3000 \\
805
+ --link ollama \\
806
+ -e OLLAMA_HOST=http://ollama:11434 \\
807
+ ghcr.io/amanasmuei/aman serve
808
+
809
+ ${pc3.bold("npm (any server):")}
810
+ npm install -g @aman_asmuei/achannel @aman_asmuei/aman-mcp
811
+ ANTHROPIC_API_KEY=sk-ant-... achannel serve
812
+
813
+ ${pc3.bold("Raspberry Pi:")}
814
+ curl -fsSL https://deb.nodesource.com/setup_22.x | sudo bash -
815
+ sudo apt install -y nodejs
816
+ npm install -g @aman_asmuei/achannel @aman_asmuei/aman-mcp
817
+ ANTHROPIC_API_KEY=sk-ant-... achannel serve`,
818
+ "Manual deployment commands"
819
+ );
820
+ }
821
+ function findPackageDir() {
822
+ let dir = new URL(".", import.meta.url).pathname;
823
+ for (let i = 0; i < 5; i++) {
824
+ if (fs6.existsSync(path4.join(dir, "Dockerfile"))) return dir;
825
+ dir = path4.dirname(dir);
826
+ }
827
+ const globalDir = path4.join(process.env.npm_config_prefix || "/usr/local", "lib/node_modules/@aman_asmuei/aman");
828
+ if (fs6.existsSync(path4.join(globalDir, "Dockerfile"))) return globalDir;
829
+ return process.cwd();
830
+ }
831
+ function copyDeployFile(pkgDir, destDir, filename) {
832
+ const src = path4.join(pkgDir, filename);
833
+ const dest = path4.join(destDir, filename);
834
+ if (fs6.existsSync(src)) {
835
+ fs6.copyFileSync(src, dest);
836
+ }
837
+ }
838
+
470
839
  // src/index.ts
471
840
  var program = new Command();
472
- program.name("aman").description("Your complete AI companion \u2014 identity, memory, and tools in one command").version("0.1.1").action(() => {
841
+ program.name("aman").description("Your complete AI companion \u2014 identity, memory, and tools in one command").version("0.3.0").action(() => {
473
842
  const ecosystem = detectEcosystem();
474
843
  if (ecosystem.acore.installed) {
475
844
  statusCommand();
@@ -479,4 +848,5 @@ program.name("aman").description("Your complete AI companion \u2014 identity, me
479
848
  });
480
849
  program.command("setup").description("Set up your AI companion (identity + memory + tools)").action(() => setupCommand());
481
850
  program.command("status").description("View your full ecosystem status").action(() => statusCommand());
851
+ program.command("deploy").description("Deploy your AI companion (Docker, systemd, or cloud)").action(() => deployCommand());
482
852
  program.parse();
@@ -0,0 +1,65 @@
1
+ # aman ecosystem — fully local with Ollama (no API key needed)
2
+ # Usage: docker compose -f docker-compose.ollama.yml up -d
3
+ #
4
+ # First run pulls llama3.2 model (~2GB download)
5
+ # Works on: Raspberry Pi 4/5 (ARM64), any Linux/Mac with Docker
6
+
7
+ services:
8
+ ollama:
9
+ image: ollama/ollama:latest
10
+ restart: unless-stopped
11
+ volumes:
12
+ - ollama-models:/root/.ollama
13
+ ports:
14
+ - "11434:11434"
15
+ # Uncomment for GPU support:
16
+ # deploy:
17
+ # resources:
18
+ # reservations:
19
+ # devices:
20
+ # - capabilities: [gpu]
21
+
22
+ ollama-init:
23
+ image: ollama/ollama:latest
24
+ depends_on:
25
+ - ollama
26
+ restart: "no"
27
+ entrypoint: >
28
+ sh -c "sleep 5 && ollama pull llama3.2"
29
+ environment:
30
+ - OLLAMA_HOST=http://ollama:11434
31
+
32
+ aman-server:
33
+ build: .
34
+ command: serve
35
+ restart: unless-stopped
36
+ depends_on:
37
+ - ollama
38
+ ports:
39
+ - "3000:3000"
40
+ environment:
41
+ - OLLAMA_HOST=http://ollama:11434
42
+ - AMAN_AI_NAME=${AMAN_AI_NAME:-Aman}
43
+ - AMAN_MODEL=${AMAN_MODEL:-llama3.2}
44
+ - TELEGRAM_BOT_TOKEN=${TELEGRAM_BOT_TOKEN:-}
45
+ - DISCORD_BOT_TOKEN=${DISCORD_BOT_TOKEN:-}
46
+ volumes:
47
+ - aman-identity:/root/.acore
48
+ - aman-memory:/root/.amem
49
+ - aman-config:/root/.aman-agent
50
+ - aman-rules:/root/.arules
51
+ - aman-workflows:/root/.aflow
52
+ - aman-eval:/root/.aeval
53
+ - aman-skills:/root/.askill
54
+ - aman-tools:/root/.akit
55
+
56
+ volumes:
57
+ ollama-models:
58
+ aman-identity:
59
+ aman-memory:
60
+ aman-config:
61
+ aman-rules:
62
+ aman-workflows:
63
+ aman-eval:
64
+ aman-skills:
65
+ aman-tools:
@@ -0,0 +1,40 @@
1
+ # aman ecosystem — full deployment
2
+ # Usage: docker compose up -d
3
+ #
4
+ # Modes:
5
+ # aman-server → always-on webhook/Telegram/Discord server
6
+ # aman-agent → interactive CLI (attach with: docker attach aman-agent)
7
+
8
+ services:
9
+ aman-server:
10
+ build: .
11
+ command: serve
12
+ restart: unless-stopped
13
+ ports:
14
+ - "3000:3000"
15
+ environment:
16
+ - ANTHROPIC_API_KEY=${ANTHROPIC_API_KEY}
17
+ - OPENAI_API_KEY=${OPENAI_API_KEY:-}
18
+ - AMAN_AI_NAME=${AMAN_AI_NAME:-Aman}
19
+ - AMAN_MODEL=${AMAN_MODEL:-claude-sonnet-4-6}
20
+ - TELEGRAM_BOT_TOKEN=${TELEGRAM_BOT_TOKEN:-}
21
+ - DISCORD_BOT_TOKEN=${DISCORD_BOT_TOKEN:-}
22
+ volumes:
23
+ - aman-identity:/root/.acore
24
+ - aman-memory:/root/.amem
25
+ - aman-config:/root/.aman-agent
26
+ - aman-rules:/root/.arules
27
+ - aman-workflows:/root/.aflow
28
+ - aman-eval:/root/.aeval
29
+ - aman-skills:/root/.askill
30
+ - aman-tools:/root/.akit
31
+
32
+ volumes:
33
+ aman-identity:
34
+ aman-memory:
35
+ aman-config:
36
+ aman-rules:
37
+ aman-workflows:
38
+ aman-eval:
39
+ aman-skills:
40
+ aman-tools:
@@ -0,0 +1,165 @@
1
+ #!/bin/sh
2
+ set -e
3
+
4
+ # aman ecosystem — Docker entrypoint
5
+ # Modes:
6
+ # agent → interactive CLI (default)
7
+ # serve → achannel webhook/Telegram/Discord server
8
+ # setup → run ecosystem setup
9
+ # status → show ecosystem status
10
+
11
+ MODE="${1:-agent}"
12
+
13
+ # Auto-create minimal identity if none exists
14
+ if [ ! -f /root/.acore/core.md ]; then
15
+ echo " First run — creating default identity..."
16
+ AI_NAME="${AMAN_AI_NAME:-Aman}"
17
+ cat > /root/.acore/core.md << EOF
18
+ # ${AI_NAME}
19
+
20
+ ## Identity
21
+ - Role: ${AI_NAME} is your AI companion
22
+ - Personality: helpful, direct, adaptive
23
+ - Communication: clear and concise
24
+ - Values: honesty, simplicity, understanding
25
+ - Boundaries: won't pretend to be human
26
+
27
+ ---
28
+
29
+ ## Relationship
30
+ - Name: [user]
31
+ - Role: [role]
32
+ - Nicknames: []
33
+ - Communication: [updated over time]
34
+ - Detail level: balanced
35
+ - Domain: [detected from project]
36
+ - Personal: []
37
+ - Learned patterns: []
38
+
39
+ ---
40
+
41
+ ## Session
42
+ - Last updated: $(date +%Y-%m-%d)
43
+ - Resume: [starting fresh]
44
+ - Active topics: []
45
+ - Recent decisions: []
46
+ - Temp notes: []
47
+
48
+ ---
49
+
50
+ ## Dynamics
51
+
52
+ ### Trust & Rapport
53
+ - Level: 3
54
+ - Trajectory: building
55
+ - Evidence: []
56
+ - Unlocked behaviors: []
57
+
58
+ ### Emotional Patterns
59
+ - Baseline energy: steady
60
+ - Stress signals: []
61
+ - Support style: problem-solve
62
+ - Current read: fresh start
63
+
64
+ ### Conflict & Repair
65
+ - History: []
66
+ - Conflict style: direct
67
+ - Learned response: []
68
+
69
+ ---
70
+
71
+ ## Context Modes
72
+
73
+ > Active mode inferred from conversation context.
74
+
75
+ ### Default
76
+ - Tone: casual-professional
77
+ - Detail: balanced
78
+ - Initiative: proactive
79
+
80
+ ---
81
+
82
+ ## Memory Lifecycle
83
+
84
+ ### Importance
85
+ - Critical: [user boundaries, core preferences]
86
+ - Persistent: [projects, tech stack]
87
+ - Ephemeral: [temporary context]
88
+
89
+ ### Size
90
+ - Target: under 2000 tokens
91
+ EOF
92
+ echo " Identity created: ${AI_NAME}"
93
+ fi
94
+
95
+ # Auto-create aman-agent config if API key is provided
96
+ if [ ! -f /root/.aman-agent/config.json ]; then
97
+ if [ -n "$ANTHROPIC_API_KEY" ]; then
98
+ MODEL="${AMAN_MODEL:-claude-sonnet-4-6}"
99
+ cat > /root/.aman-agent/config.json << EOF
100
+ {
101
+ "provider": "anthropic",
102
+ "apiKey": "${ANTHROPIC_API_KEY}",
103
+ "model": "${MODEL}",
104
+ "hooks": {
105
+ "memoryRecall": true,
106
+ "sessionResume": true,
107
+ "rulesCheck": true,
108
+ "workflowSuggest": true,
109
+ "evalPrompt": false,
110
+ "autoSessionSave": true,
111
+ "extractMemories": true,
112
+ "featureHints": true,
113
+ "personalityAdapt": true
114
+ }
115
+ }
116
+ EOF
117
+ echo " Config created: Anthropic / ${MODEL}"
118
+ elif [ -n "$OPENAI_API_KEY" ]; then
119
+ MODEL="${AMAN_MODEL:-gpt-4o}"
120
+ cat > /root/.aman-agent/config.json << EOF
121
+ {
122
+ "provider": "openai",
123
+ "apiKey": "${OPENAI_API_KEY}",
124
+ "model": "${MODEL}",
125
+ "hooks": {
126
+ "memoryRecall": true,
127
+ "sessionResume": true,
128
+ "rulesCheck": true,
129
+ "workflowSuggest": true,
130
+ "evalPrompt": false,
131
+ "autoSessionSave": true,
132
+ "extractMemories": true,
133
+ "featureHints": true,
134
+ "personalityAdapt": true
135
+ }
136
+ }
137
+ EOF
138
+ echo " Config created: OpenAI / ${MODEL}"
139
+ fi
140
+ fi
141
+
142
+ case "$MODE" in
143
+ agent)
144
+ echo " Starting aman-agent (interactive)..."
145
+ exec aman-agent
146
+ ;;
147
+ serve)
148
+ echo " Starting achannel server on :3000..."
149
+ exec achannel serve
150
+ ;;
151
+ setup)
152
+ exec aman setup
153
+ ;;
154
+ status)
155
+ exec aman status
156
+ ;;
157
+ sh|bash)
158
+ exec /bin/sh
159
+ ;;
160
+ *)
161
+ echo "Unknown mode: $MODE"
162
+ echo "Usage: docker run aman [agent|serve|setup|status|sh]"
163
+ exit 1
164
+ ;;
165
+ esac
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aman_asmuei/aman",
3
- "version": "0.1.1",
3
+ "version": "0.3.0",
4
4
  "description": "Your complete AI companion — identity, memory, and tools in one command",
5
5
  "type": "module",
6
6
  "bin": {
@@ -10,7 +10,12 @@
10
10
  "files": [
11
11
  "dist",
12
12
  "bin",
13
- "template"
13
+ "template",
14
+ "deploy",
15
+ "Dockerfile",
16
+ "docker-entrypoint.sh",
17
+ "docker-compose.yml",
18
+ "docker-compose.ollama.yml"
14
19
  ],
15
20
  "scripts": {
16
21
  "build": "tsup",