@agentprojectcontext/apx 1.9.0 → 1.10.1

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/README.md CHANGED
@@ -26,7 +26,7 @@ npm install -g apx
26
26
  # In any directory with an AGENTS.md
27
27
  apx init
28
28
 
29
- # Spawn an agent with a full Claude Code runtime
29
+ # Spawn an agent with a full external runtime
30
30
  apx run sofia --runtime claude-code "Review the open PRs and summarize them"
31
31
 
32
32
  # Or a quick one-shot LLM exec
@@ -84,6 +84,7 @@ apx memory <slug> # read agent memory
84
84
  apx memory <slug> --append "<note>" # append to memory
85
85
 
86
86
  apx run <slug> --runtime claude-code "<prompt>" # full runtime session
87
+ apx run <slug> --runtime cursor-agent "<prompt>" # Cursor Agent runtime
87
88
  apx exec <slug> "<prompt>" # quick LLM call
88
89
 
89
90
  apx session list <slug> # list past sessions
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agentprojectcontext/apx",
3
- "version": "1.9.0",
3
+ "version": "1.10.1",
4
4
  "description": "APX — unified CLI + daemon for the Agent Project Context (APC) standard.",
5
5
  "publishConfig": {
6
6
  "access": "public"
@@ -26,6 +26,11 @@ apx mcp list # MCP servers available to this project
26
26
  # Full external session (best for complex, multi-step tasks)
27
27
  apx run <slug> --runtime claude-code "<prompt>"
28
28
  apx run <slug> --runtime codex "<prompt>"
29
+ apx run <slug> --runtime opencode "<prompt>"
30
+ apx run <slug> --runtime aider "<prompt>"
31
+ apx run <slug> --runtime cursor-agent "<prompt>"
32
+ apx run <slug> --runtime gemini-cli "<prompt>"
33
+ apx run <slug> --runtime qwen-code "<prompt>"
29
34
 
30
35
  # Quick one-shot LLM call (requires engine API key in ~/.apx/config.json)
31
36
  apx exec <slug> "<prompt>"
@@ -2,6 +2,8 @@
2
2
  import fs from "node:fs";
3
3
  import path from "node:path";
4
4
  import { findApfRoot } from "../../core/parser.js";
5
+ import { http } from "../http.js";
6
+ import { resolveProjectId } from "./project.js";
5
7
 
6
8
  function commandsDir(root) {
7
9
  return path.join(root, ".apc", "commands");
@@ -13,9 +15,28 @@ function listCommandFiles(root) {
13
15
  return fs.readdirSync(dir).filter((f) => f.endsWith(".md")).sort();
14
16
  }
15
17
 
16
- export function cmdCommandList() {
18
+ async function resolveCommandRoot(args = {}) {
19
+ const explicitProject = args?.flags?.project;
20
+ if (explicitProject !== undefined && explicitProject !== null && explicitProject !== "") {
21
+ const pid = await resolveProjectId(explicitProject);
22
+ const projects = await http.get("/projects");
23
+ const project = projects.find((p) => p.id === pid);
24
+ if (!project) throw new Error(`project ${pid} not found`);
25
+ return project.path;
26
+ }
27
+
17
28
  const root = findApfRoot();
18
- if (!root) throw new Error("not inside an APC project");
29
+ if (root) return root;
30
+
31
+ const pid = await resolveProjectId();
32
+ const projects = await http.get("/projects");
33
+ const project = projects.find((p) => p.id === pid);
34
+ if (!project) throw new Error(`project ${pid} not found`);
35
+ return project.path;
36
+ }
37
+
38
+ export async function cmdCommandList(args = {}) {
39
+ const root = await resolveCommandRoot(args);
19
40
  const files = listCommandFiles(root);
20
41
  if (files.length === 0) {
21
42
  console.log("(no commands — add .md files to .apc/commands/)");
@@ -31,11 +52,10 @@ export function cmdCommandList() {
31
52
  }
32
53
  }
33
54
 
34
- export function cmdCommandShow(args) {
55
+ export async function cmdCommandShow(args) {
35
56
  const name = args._[0];
36
57
  if (!name) throw new Error("apx command show: missing <name>");
37
- const root = findApfRoot();
38
- if (!root) throw new Error("not inside an APC project");
58
+ const root = await resolveCommandRoot(args);
39
59
  const file = path.join(commandsDir(root), `${name}.md`);
40
60
  if (!fs.existsSync(file)) throw new Error(`command "${name}" not found in .apc/commands/`);
41
61
  process.stdout.write(fs.readFileSync(file, "utf8"));
@@ -5,7 +5,7 @@ export async function cmdRun(args) {
5
5
  const slug = args._[0];
6
6
  if (!slug) throw new Error("apx run: usage: apx run <agent> --runtime <id> \"<prompt>\"");
7
7
  const runtime = args.flags.runtime === true ? null : args.flags.runtime;
8
- if (!runtime) throw new Error("apx run: --runtime required (claude-code | codex | opencode | aider)");
8
+ if (!runtime) throw new Error("apx run: --runtime required (claude-code | codex | opencode | aider | cursor-agent | gemini-cli | qwen-code)");
9
9
 
10
10
  let prompt = args._.slice(1).join(" ").trim();
11
11
  if (!prompt || prompt === "-") {
@@ -102,16 +102,21 @@ export async function cmdSys(args) {
102
102
  return;
103
103
  }
104
104
 
105
- if (handleEditingKey(str, key, state, renderScreen)) return;
106
-
107
- if (key.name === "return") {
105
+ if (isReturnKey(key)) {
108
106
  isRequesting = true;
109
107
  await submitPrompt(pid, state, previousMessages, renderScreen, close);
110
108
  isRequesting = false;
109
+ return;
111
110
  }
111
+
112
+ if (handleEditingKey(str, key, state, renderScreen)) return;
112
113
  });
113
114
  }
114
115
 
116
+ export function isReturnKey(key) {
117
+ return key?.name === "return" || key?.name === "enter";
118
+ }
119
+
115
120
  async function handlePaletteKey(key, cfg, state, renderScreen, close) {
116
121
  if (key.name === "up") {
117
122
  state.paletteSelection = Math.max(0, state.paletteSelection - 1);
@@ -189,7 +194,7 @@ function loadModelOptions(cfg, state, renderScreen) {
189
194
  });
190
195
  }
191
196
 
192
- function handleEditingKey(str, key, state, renderScreen) {
197
+ export function handleEditingKey(str, key, state, renderScreen) {
193
198
  if (key.name === "tab") {
194
199
  state.currentModeIdx = (state.currentModeIdx + 1) % MODES.length;
195
200
  renderScreen();
@@ -261,7 +266,7 @@ function handleEditingKey(str, key, state, renderScreen) {
261
266
  return true;
262
267
  }
263
268
 
264
- if (str && str.length === 1 && !key.ctrl && !key.meta) {
269
+ if (str && str.length === 1 && !key.ctrl && !key.meta && str >= " ") {
265
270
  state.inputText = state.inputText.slice(0, state.cursorIndex) + str + state.inputText.slice(state.cursorIndex);
266
271
  state.cursorIndex += str.length;
267
272
  renderScreen();
package/src/cli/index.js CHANGED
@@ -60,7 +60,7 @@ import {
60
60
  cmdConversationsList,
61
61
  cmdConversationsGet,
62
62
  } from "./commands/chat.js";
63
- import { cmdSys } from "./commands/sys.js";
63
+ import { cmdSys as cmdCode } from "./commands/sys.js";
64
64
  import { cmdRun, cmdEnvDetect } from "./commands/runtime.js";
65
65
  import { cmdSend, cmdConnections } from "./commands/a2a.js";
66
66
  import {
@@ -184,7 +184,7 @@ const HELP_TOPICS = new Map(Object.entries({
184
184
  title: "apx project add",
185
185
  summary: "Register a project with the APX daemon.",
186
186
  usage: ["apx project add [path]"],
187
- examples: ["apx project add .", "apx add project ../repo"],
187
+ examples: ["apx project add .", "apx project add ../repo"],
188
188
  }),
189
189
  "project list": topic({
190
190
  title: "apx project list",
@@ -204,19 +204,6 @@ const HELP_TOPICS = new Map(Object.entries({
204
204
  usage: ["apx project rebuild [id]"],
205
205
  examples: ["apx project rebuild", "apx project rebuild default"],
206
206
  }),
207
- add: topic({
208
- title: "apx add",
209
- summary: "Friendly alias namespace for add operations.",
210
- usage: ["apx add project [path]"],
211
- commands: [["project [path]", "Alias for apx project add [path]."]],
212
- examples: ["apx add project ."],
213
- }),
214
- "add project": topic({
215
- title: "apx add project",
216
- summary: "Alias for apx project add.",
217
- usage: ["apx add project [path]"],
218
- examples: ["apx add project ."],
219
- }),
220
207
  agent: topic({
221
208
  title: "apx agent",
222
209
  summary: "Create, inspect, import, and vault agent definitions.",
@@ -298,7 +285,7 @@ const HELP_TOPICS = new Map(Object.entries({
298
285
  }),
299
286
  identity: topic({
300
287
  title: "apx identity",
301
- summary: "Read or edit daemon identity fields.",
288
+ summary: "Read or edit APX profile identity fields.",
302
289
  usage: ["apx identity <show|set|wizard> [args]"],
303
290
  commands: [
304
291
  ["show", "Print current identity."],
@@ -309,13 +296,13 @@ const HELP_TOPICS = new Map(Object.entries({
309
296
  }),
310
297
  "identity show": topic({
311
298
  title: "apx identity show",
312
- summary: "Print current daemon identity.",
299
+ summary: "Print current APX profile identity.",
313
300
  usage: ["apx identity show"],
314
301
  examples: ["apx identity show"],
315
302
  }),
316
303
  "identity set": topic({
317
304
  title: "apx identity set",
318
- summary: "Set one daemon identity field.",
305
+ summary: "Set one APX profile identity field.",
319
306
  usage: ["apx identity set <key> <value>"],
320
307
  examples: ["apx identity set agent_name Ada", "apx identity set owner_name Sam"],
321
308
  }),
@@ -364,7 +351,7 @@ const HELP_TOPICS = new Map(Object.entries({
364
351
  }),
365
352
  permission: topic({
366
353
  title: "apx permission",
367
- summary: "Show or set super-agent permission mode.",
354
+ summary: "Show or set APX tool permission mode.",
368
355
  usage: ["apx permission show", "apx permission set <total|automatico|permiso>"],
369
356
  commands: [
370
357
  ["show", "Print current permission mode."],
@@ -374,13 +361,13 @@ const HELP_TOPICS = new Map(Object.entries({
374
361
  }),
375
362
  "permission show": topic({
376
363
  title: "apx permission show",
377
- summary: "Print current super-agent permission mode.",
364
+ summary: "Print current APX tool permission mode.",
378
365
  usage: ["apx permission show"],
379
366
  examples: ["apx permission show"],
380
367
  }),
381
368
  "permission set": topic({
382
369
  title: "apx permission set",
383
- summary: "Set super-agent permission mode.",
370
+ summary: "Set APX tool permission mode.",
384
371
  usage: ["apx permission set <total|automatico|permiso>"],
385
372
  examples: ["apx permission set permiso"],
386
373
  }),
@@ -702,14 +689,14 @@ const HELP_TOPICS = new Map(Object.entries({
702
689
  ],
703
690
  examples: ["apx chat reviewer", "apx chat reviewer --conversation abc123"],
704
691
  }),
705
- sys: topic({
706
- title: "apx sys",
707
- summary: "Start an interactive super-agent chat REPL with system and workspace context.",
708
- usage: ["apx sys [--project <name|id|path>]"],
692
+ code: topic({
693
+ title: "apx code",
694
+ summary: "Start the APX terminal coding assistant with system and workspace context.",
695
+ usage: ["apx code [--project <name|id|path>]"],
709
696
  options: [
710
697
  ["--project <name|id|path>", "Pin command to a specific project."],
711
698
  ],
712
- examples: ["apx sys", "apx sys --project default"],
699
+ examples: ["apx code", "apx code --project default"],
713
700
  }),
714
701
  conversations: topic({
715
702
  title: "apx conversations",
@@ -745,9 +732,9 @@ const HELP_TOPICS = new Map(Object.entries({
745
732
  run: topic({
746
733
  title: "apx run",
747
734
  summary: "Launch a full external runtime session for an agent.",
748
- usage: ["apx run <agent> --runtime <claude-code|codex|opencode|aider> \"<prompt>\" [--timeout <seconds>] [--project <name|id|path>]"],
735
+ usage: ["apx run <agent> --runtime <claude-code|codex|opencode|aider|cursor-agent|gemini-cli|qwen-code> \"<prompt>\" [--timeout <seconds>] [--project <name|id|path>]"],
749
736
  options: [
750
- ["--runtime <id>", "Runtime CLI to launch: claude-code, codex, opencode, aider."],
737
+ ["--runtime <id>", "Runtime CLI to launch: claude-code, codex, opencode, aider, cursor-agent, gemini-cli, qwen-code."],
751
738
  ["--timeout <seconds>", "Runtime timeout."],
752
739
  ["--project <name|id|path>", "Pin command to a specific project."],
753
740
  ],
@@ -779,17 +766,10 @@ const HELP_TOPICS = new Map(Object.entries({
779
766
  connections: topic({
780
767
  title: "apx connections",
781
768
  summary: "Show an agent communication map.",
782
- usage: ["apx connections <agent> [--project <name|id|path>]", "apx graph <agent> [--project <name|id|path>]"],
769
+ usage: ["apx connections <agent> [--project <name|id|path>]"],
783
770
  options: [["--project <name|id|path>", "Pin command to a specific project."]],
784
771
  examples: ["apx connections reviewer"],
785
772
  }),
786
- graph: topic({
787
- title: "apx graph",
788
- summary: "Alias for apx connections.",
789
- usage: ["apx graph <agent> [--project <name|id|path>]"],
790
- options: [["--project <name|id|path>", "Pin command to a specific project."]],
791
- examples: ["apx graph reviewer"],
792
- }),
793
773
  routine: topic({
794
774
  title: "apx routine",
795
775
  summary: "Manage scheduled APX routines.",
@@ -931,11 +911,12 @@ const HELP_TOPICS = new Map(Object.entries({
931
911
  command: topic({
932
912
  title: "apx command",
933
913
  summary: "List or show workflow commands from .apc/commands/.",
934
- usage: ["apx command [list]", "apx command show <name>"],
914
+ usage: ["apx command [list] [--project <name|id|path>]", "apx command show <name> [--project <name|id|path>]"],
935
915
  commands: [
936
916
  ["list | ls", "List workflow commands."],
937
917
  ["show | get <name>", "Print one command file."],
938
918
  ],
919
+ options: [["--project <name|id|path>", "Pin command to a specific project; defaults to current APC project or default."]],
939
920
  examples: ["apx command list", "apx command show release"],
940
921
  }),
941
922
  commands: topic({
@@ -947,13 +928,15 @@ const HELP_TOPICS = new Map(Object.entries({
947
928
  "command list": topic({
948
929
  title: "apx command list",
949
930
  summary: "List workflow commands in .apc/commands/.",
950
- usage: ["apx command list", "apx command ls"],
931
+ usage: ["apx command list [--project <name|id|path>]", "apx command ls [--project <name|id|path>]"],
932
+ options: [["--project <name|id|path>", "Pin command to a specific project; defaults to current APC project or default."]],
951
933
  examples: ["apx command list"],
952
934
  }),
953
935
  "command show": topic({
954
936
  title: "apx command show",
955
937
  summary: "Print one workflow command file.",
956
- usage: ["apx command show <name>", "apx command get <name>"],
938
+ usage: ["apx command show <name> [--project <name|id|path>]", "apx command get <name> [--project <name|id|path>]"],
939
+ options: [["--project <name|id|path>", "Pin command to a specific project; defaults to current APC project or default."]],
957
940
  examples: ["apx command show release"],
958
941
  }),
959
942
  skills: topic({
@@ -1019,6 +1002,7 @@ const HELP_TOPICS = new Map(Object.entries({
1019
1002
  const HELP_ALIASES = new Map(Object.entries({
1020
1003
  "project ls": "project list",
1021
1004
  "project rm": "project remove",
1005
+ "sys": "code",
1022
1006
  "agent ls": "agent list",
1023
1007
  "agent show": "agent get",
1024
1008
  "agent vault ls": "agent vault list",
@@ -1074,11 +1058,12 @@ function buildHelp(version) {
1074
1058
  hCmd("apx setup", 36, "interactive wizard: provider → model → channels → daemon (alias: install)"),
1075
1059
  hCmd("apx status", 36, "full system status: daemon, super-agent, engines, telegram, projects"),
1076
1060
  hCmd("apx update", 36, "check for updates and upgrade (alias: upgrade)"),
1061
+
1062
+ hSec("Projects"),
1077
1063
  hCmd("apx project add [path]", 36, "register a project with the daemon"),
1078
1064
  hCmd("apx project list", 36, ""),
1079
1065
  hCmd("apx project remove <id>", 36, ""),
1080
1066
  hCmd("apx project rebuild [id]", 36, "rebuild project index from filesystem"),
1081
- hCmd("apx add project [path]", 36, "alias for: apx project add"),
1082
1067
 
1083
1068
  hSec("Agents"),
1084
1069
  hCmd("apx agent add <slug>", 36, "--role R --model M --skills a,b --language es-AR --description D"),
@@ -1088,15 +1073,16 @@ function buildHelp(version) {
1088
1073
  hCmd("apx agent vault list", 36, ""),
1089
1074
  hCmd("apx agent vault add", 36, ""),
1090
1075
 
1091
- hSec("Identity & Config"),
1092
- hCmd("apx identity show", 36, "print current agent identity (name, owner, personality)"),
1076
+ hSec("APX Profile"),
1077
+ hCmd("apx identity show", 36, "print current APX identity (name, owner, personality)"),
1093
1078
  hCmd("apx identity set <k> <v>", 36, "set identity field"),
1094
1079
  hCmd("apx identity wizard", 36, "interactive identity setup"),
1080
+
1081
+ hSec("Config"),
1095
1082
  hCmd("apx config show", 36, "--effective --only-overrides"),
1096
- hCmd("apx config set <key> <val>", 36, "set key in .apc/config.json (JSON-aware)"),
1097
- hCmd("apx permission show", 36, "show super-agent permission mode"),
1083
+ hCmd("apx config set|unset", 36, "<key> [value] edit .apc/config.json (JSON-aware)"),
1084
+ hCmd("apx permission show", 36, "show APX tool permission mode"),
1098
1085
  hCmd("apx permission set <mode>", 36, "mode: total | automatico | permiso"),
1099
- hCmd("apx config unset <key>", 36, "remove key from .apc/config.json"),
1100
1086
 
1101
1087
  hSec("Memory"),
1102
1088
  hCmd("apx memory <slug>", 36, "print memory.md"),
@@ -1123,7 +1109,7 @@ function buildHelp(version) {
1123
1109
  hCmd("apx mcp tools <name>", 36, "list available tools"),
1124
1110
  hCmd("apx mcp check", 36, "audit multi-source merge"),
1125
1111
 
1126
- hSec("Daemon"),
1112
+ hSec("Daemon Service"),
1127
1113
  hCmd("apx daemon start", 36, ""),
1128
1114
  hCmd("apx daemon stop", 36, ""),
1129
1115
  hCmd("apx daemon status", 36, ""),
@@ -1139,22 +1125,21 @@ function buildHelp(version) {
1139
1125
  hCmd("apx messages chat", 36, "--channel telegram -n 50"),
1140
1126
  hCmd("apx messages search \"q\"", 36, ""),
1141
1127
 
1142
- hSec("LLM / Chat"),
1143
- hCmd("apx exec <agent> \"prompt\"",36, "--model <id> --max-tokens N --temperature T"),
1144
- hCmd("apx chat <agent>", 36, "--conversation <id> --model <id> (interactive REPL)"),
1145
- hCmd("apx sys", 36, "super-agent chat w/ system+workspace context"),
1146
- hCmd("apx conversations list", 36, "<agent>"),
1128
+ hSec("LLM / Code"),
1129
+ hCmd("apx code", 36, "APX terminal coding assistant"),
1130
+ hCmd("apx exec <agent> \"prompt\"",36, "one-shot agent call --model <id> --max-tokens N"),
1131
+ hCmd("apx chat <agent>", 36, "interactive agent REPL --conversation <id>"),
1132
+ hCmd("apx conversations list", 36, "stored exec/chat conversations for <agent>"),
1147
1133
  hCmd("apx conversations get", 36, "<agent> <id>"),
1148
1134
 
1149
1135
  hSec("Runtimes"),
1150
1136
  hCmd("apx run <agent>", 36, "--runtime <id> \"prompt\" --timeout <s>"),
1151
- ` ${H.DI}runtimes: claude-code | codex | opencode | aider${H.R}`,
1137
+ ` ${H.DI}runtimes: claude-code | codex | opencode | aider | cursor-agent | gemini-cli | qwen-code${H.R}`,
1152
1138
  hCmd("apx env detect", 36, "which agent CLIs are installed"),
1153
1139
 
1154
1140
  hSec("Agent-to-Agent"),
1155
1141
  hCmd("apx send <from> <to> \"msg\"",36, "--deliver log A2A message; --deliver runs target engine"),
1156
1142
  hCmd("apx connections <agent>", 36, "mental map: who/how/when this agent talked"),
1157
- hCmd("apx graph <agent>", 36, "alias for connections"),
1158
1143
 
1159
1144
  hSec("Routines & Pipeline"),
1160
1145
  hCmd("apx routine list", 36, "list routines + next/last run"),
@@ -1452,8 +1437,9 @@ async function dispatch(cmd, rest) {
1452
1437
  await cmdChat(parseArgs(rest));
1453
1438
  break;
1454
1439
 
1440
+ case "code":
1455
1441
  case "sys":
1456
- await cmdSys(parseArgs(rest));
1442
+ await cmdCode(parseArgs(rest));
1457
1443
  break;
1458
1444
 
1459
1445
  case "conversations":
@@ -1482,7 +1468,6 @@ async function dispatch(cmd, rest) {
1482
1468
  break;
1483
1469
 
1484
1470
  case "connections":
1485
- case "graph":
1486
1471
  await cmdConnections(parseArgs(rest));
1487
1472
  break;
1488
1473
 
@@ -1543,8 +1528,8 @@ async function dispatch(cmd, rest) {
1543
1528
  case "commands": {
1544
1529
  const sub = rest[0];
1545
1530
  const a = parseArgs(rest.slice(1));
1546
- if (!sub || sub === "list" || sub === "ls") cmdCommandList();
1547
- else if (sub === "show" || sub === "get") cmdCommandShow(a);
1531
+ if (!sub || sub === "list" || sub === "ls") await cmdCommandList(a);
1532
+ else if (sub === "show" || sub === "get") await cmdCommandShow(a);
1548
1533
  else die(`unknown command subcommand: ${sub}`);
1549
1534
  break;
1550
1535
  }
@@ -1563,14 +1548,6 @@ async function dispatch(cmd, rest) {
1563
1548
  await cmdIdentity(parseArgs(rest));
1564
1549
  break;
1565
1550
 
1566
- case "add": {
1567
- // apx add <domain> [...args] — consistent alternative to apx <domain> add
1568
- const sub = rest[0];
1569
- if (sub === "project") await cmdProjectAdd(parseArgs(rest.slice(1)));
1570
- else die(`unknown 'add' subcommand: ${sub || "(none)"} — try: project`);
1571
- break;
1572
- }
1573
-
1574
1551
  case "status":
1575
1552
  await cmdStatus();
1576
1553
  return; // skip checkForUpdate after status (avoid noise)
@@ -92,8 +92,8 @@ sanitized fact to `.apc/agents/<slug>/memory.md` only when useful and safe.
92
92
  ## APX
93
93
 
94
94
  APX can provide a local daemon, MCP management, Telegram bridge, routines, and runtime dispatch
95
- across Codex, Claude Code, OpenCode, Aider, or direct LLM engines. Those are APX runtime features,
96
- not APC portable-core requirements.
95
+ across Codex, Claude Code, OpenCode, Aider, Cursor Agent, Gemini CLI, Qwen Code, or direct LLM
96
+ engines. Those are APX runtime features, not APC portable-core requirements.
97
97
 
98
98
  The APX super-agent uses `~/.apx/projects/default` for system-level work when no project is named.
99
99
  APX routines can run heartbeat, shell, Telegram, project agent, or super-agent tasks on a schedule.
@@ -26,6 +26,10 @@ Use `apx run` only when:
26
26
  apx run <slug> --runtime claude-code "<prompt>"
27
27
  apx run <slug> --runtime codex "<prompt>"
28
28
  apx run <slug> --runtime opencode "<prompt>"
29
+ apx run <slug> --runtime aider "<prompt>"
30
+ apx run <slug> --runtime cursor-agent "<prompt>"
31
+ apx run <slug> --runtime gemini-cli "<prompt>"
32
+ apx run <slug> --runtime qwen-code "<prompt>"
29
33
 
30
34
  # Example: run the qa agent in codex with a specific task
31
35
  apx run qa --runtime codex "run the full test suite and report failures"
@@ -84,7 +88,7 @@ apx messages tail --agent <slug> -n 20
84
88
  Message rows expose `type` (`user`, `agent`, `tool`, `system`) and `actor_id`; use `messages chat`
85
89
  when you need a readable transcript.
86
90
 
87
- ## Super-agent permissions
91
+ ## APX tool permissions
88
92
 
89
93
  ```bash
90
94
  apx permission show
@@ -1,4 +1,5 @@
1
- // Helpers that wrap external runtimes (Claude Code, Codex, OpenCode, Aider)
1
+ // Helpers that wrap external runtimes (Claude Code, Codex, OpenCode, Aider,
2
+ // Cursor Agent, Gemini CLI, Qwen Code)
2
3
  // with APC awareness:
3
4
  //
4
5
  // 1. Create an APX runtime session BEFORE the runtime starts.
@@ -6,7 +7,7 @@
6
7
  // runtime knows the session id, the cwd of the project, and the apx
7
8
  // commands it can use to update memory / append session notes.
8
9
  // 3. After the runtime returns, capture the external transcript path
9
- // (Claude Code gives one, Codex/OpenCode/Aider don't yet) and write it
10
+ // (Claude Code gives one; most other runtimes don't yet) and write it
10
11
  // into the APX session frontmatter.
11
12
  // 4. Close the session with a synthesised result (truncated stdout).
12
13
  //
@@ -11,6 +11,7 @@ const PROBES = [
11
11
  { id: "aider", binary: "aider", args: ["--version"], category: "runtime" },
12
12
  { id: "gemini-cli", binary: "gemini", args: ["--version"], category: "runtime" },
13
13
  { id: "cursor-agent",binary: "cursor-agent", args: ["--version"], category: "runtime" },
14
+ { id: "qwen-code", binary: "qwen", args: ["--version"], category: "runtime" },
14
15
 
15
16
  // Local LLM runners (engines/)
16
17
  { id: "ollama", binary: "ollama", args: ["--version"], category: "engine" },
@@ -0,0 +1,34 @@
1
+ // Cursor Agent runtime adapter. Uses print mode for non-interactive runs:
2
+ // cursor-agent --print --output-format text --trust --force "<prompt>"
3
+ // Reference: https://docs.cursor.com/en/cli/headless
4
+
5
+ import { runProcess } from "./_spawn.js";
6
+
7
+ export default {
8
+ id: "cursor-agent",
9
+ binary: "cursor-agent",
10
+ versionFlag: "--version",
11
+
12
+ async run({ system, prompt, cwd, env, timeoutMs }) {
13
+ const fullPrompt = system ? `${system}\n\n---\n\n${prompt}` : prompt;
14
+ const r = await runProcess({
15
+ command: "cursor-agent",
16
+ args: [
17
+ "--print",
18
+ "--output-format", "text",
19
+ "--trust",
20
+ "--force",
21
+ fullPrompt,
22
+ ],
23
+ cwd,
24
+ env,
25
+ timeoutMs,
26
+ });
27
+ return {
28
+ exitCode: r.exitCode,
29
+ output: r.stdout.trim(),
30
+ stderr: r.stderr,
31
+ externalSessionPath: null,
32
+ };
33
+ },
34
+ };
@@ -0,0 +1,32 @@
1
+ // Gemini CLI runtime adapter. Uses headless prompt mode:
2
+ // gemini --prompt "<prompt>" --output-format text --approval-mode yolo
3
+ // Reference: https://google-gemini.github.io/gemini-cli/docs/cli/headless.html
4
+
5
+ import { runProcess } from "./_spawn.js";
6
+
7
+ export default {
8
+ id: "gemini-cli",
9
+ binary: "gemini",
10
+ versionFlag: "--version",
11
+
12
+ async run({ system, prompt, cwd, env, timeoutMs }) {
13
+ const fullPrompt = system ? `${system}\n\n---\n\n${prompt}` : prompt;
14
+ const r = await runProcess({
15
+ command: "gemini",
16
+ args: [
17
+ "--prompt", fullPrompt,
18
+ "--output-format", "text",
19
+ "--approval-mode", "yolo",
20
+ ],
21
+ cwd,
22
+ env,
23
+ timeoutMs,
24
+ });
25
+ return {
26
+ exitCode: r.exitCode,
27
+ output: r.stdout.trim(),
28
+ stderr: r.stderr,
29
+ externalSessionPath: null,
30
+ };
31
+ },
32
+ };
@@ -1,5 +1,6 @@
1
1
  // Runtime adapters: spawn external agent CLIs (Claude Code, Codex, OpenCode,
2
- // Aider, ...) with the agent's system prompt + the prompt we want to run, and
2
+ // Aider, Cursor Agent, Gemini CLI, Qwen Code, ...) with the agent's system
3
+ // prompt + the prompt we want to run, and
3
4
  // capture their output. Unlike engines/ — which talk directly to model APIs —
4
5
  // runtimes/ delegate the whole conversation to the external tool. APX only
5
6
  // records the invocation, the prompt, the captured output, and where the tool
@@ -18,12 +19,18 @@ import claudeCode from "./claude-code.js";
18
19
  import codex from "./codex.js";
19
20
  import opencode from "./opencode.js";
20
21
  import aider from "./aider.js";
22
+ import cursorAgent from "./cursor-agent.js";
23
+ import geminiCli from "./gemini-cli.js";
24
+ import qwenCode from "./qwen-code.js";
21
25
 
22
26
  const REGISTRY = {
23
27
  "claude-code": claudeCode,
24
28
  codex,
25
29
  opencode,
26
30
  aider,
31
+ "cursor-agent": cursorAgent,
32
+ "gemini-cli": geminiCli,
33
+ "qwen-code": qwenCode,
27
34
  };
28
35
 
29
36
  export const RUNTIME_IDS = Object.keys(REGISTRY);
@@ -0,0 +1,36 @@
1
+ // Qwen Code runtime adapter. Uses non-interactive mode:
2
+ // qwen --output-format text --approval-mode yolo "<prompt>"
3
+ // Reference: https://qwenlm.github.io/qwen-code-docs/en/cli/index
4
+
5
+ import { runProcess } from "./_spawn.js";
6
+
7
+ export default {
8
+ id: "qwen-code",
9
+ binary: "qwen",
10
+ versionFlag: "--version",
11
+
12
+ async run({ system, prompt, cwd, env, timeoutMs }) {
13
+ const args = [
14
+ "--output-format", "text",
15
+ "--approval-mode", "yolo",
16
+ ];
17
+ if (system) {
18
+ args.push("--append-system-prompt", system);
19
+ }
20
+ args.push(prompt);
21
+
22
+ const r = await runProcess({
23
+ command: "qwen",
24
+ args,
25
+ cwd,
26
+ env,
27
+ timeoutMs,
28
+ });
29
+ return {
30
+ exitCode: r.exitCode,
31
+ output: r.stdout.trim(),
32
+ stderr: r.stderr,
33
+ externalSessionPath: null,
34
+ };
35
+ },
36
+ };
@@ -67,7 +67,7 @@ export default {
67
67
  type: "function",
68
68
  function: {
69
69
  name: "call_runtime",
70
- description: "Spawn an external CLI runtime (Claude Code, Codex, OpenCode, Aider), optionally impersonating an APC agent.",
70
+ description: "Spawn an external CLI runtime (Claude Code, Codex, OpenCode, Aider, Cursor Agent, Gemini CLI, Qwen Code), optionally impersonating an APC agent.",
71
71
  parameters: {
72
72
  type: "object",
73
73
  properties: {
@@ -75,7 +75,7 @@ export default {
75
75
  agent: { type: "string", description: "Optional APC agent slug from AGENTS.md, not runtime name. Omit when the user did not name an agent." },
76
76
  runtime: {
77
77
  type: "string",
78
- enum: ["claude-code", "codex", "opencode", "aider"],
78
+ enum: RUNTIME_IDS,
79
79
  description: "external CLI runtime",
80
80
  },
81
81
  prompt: { type: "string" },
@@ -7,7 +7,7 @@ export default {
7
7
  type: "function",
8
8
  function: {
9
9
  name: "set_identity",
10
- description: "Update daemon identity fields. Persists to ~/.apx/identity.json.",
10
+ description: "Update APX profile identity fields. Persists to ~/.apx/identity.json.",
11
11
  parameters: {
12
12
  type: "object",
13
13
  properties: {
@@ -9,7 +9,7 @@ export default {
9
9
  type: "function",
10
10
  function: {
11
11
  name: "set_permission_mode",
12
- description: "Set the super-agent permission mode in ~/.apx/config.json. Modes: total, automatico, permiso.",
12
+ description: "Set APX tool permission mode in ~/.apx/config.json. Modes: total, automatico, permiso.",
13
13
  parameters: {
14
14
  type: "object",
15
15
  properties: {
@@ -54,7 +54,7 @@ HARD RULES (do not deviate):
54
54
  8. You DO see recent prior turns of this chat as previous messages when applicable. **Use them ONLY to disambiguate references** (e.g. "el primero" → first project mentioned earlier). For ANY factual data — agent details, MCP details, file contents, memory — RE-CALL the tool. Past turns are context, not a cache. Models change, agents change, files change.
55
55
  9. /reset or /new from the user means "forget previous turns and answer this one fresh" — if you see those prefixes the operator already cleared the context for you.
56
56
  10. DELEGATION RULE: when the user asks an agent to do a task, use call_agent (unless they specify opening it in a runtime, then see rule 11).
57
- 11. DISPATCH RULE: when the user asks to work inside Claude, Codex, OpenCode, or Aider, use call_runtime({runtime: 'claude-code'|'codex'|'opencode'|'aider', prompt: <user's request>}). If they explicitly name an agent to spawn, pass agent: <slug>. If they don't name an agent, DO NOT pass an agent argument. When an agent is passed, its memory + skills become the system prompt of the runtime.
57
+ 11. DISPATCH RULE: when the user asks to work inside Claude, Codex, OpenCode, Aider, Cursor, Gemini CLI, or Qwen Code, use call_runtime({runtime: 'claude-code'|'codex'|'opencode'|'aider'|'cursor-agent'|'gemini-cli'|'qwen-code', prompt: <user's request>}). If they explicitly name an agent to spawn, pass agent: <slug>. If they don't name an agent, DO NOT pass an agent argument. When an agent is passed, its memory + skills become the system prompt of the runtime.
58
58
  12. PROJECT RULE: when the user gives no project, use project "default". Do not infer a non-default project from old chat history unless the user references it. If they mention a path or project name, look it up or add it with add_project.
59
59
  13. VAULT RULE: when the user wants a new existing agent/template, call list_vault_agents first. If a suitable vault agent exists, import_agent into the chosen project. If none fits, say briefly what is missing.
60
60
  14. NO-PENDING RULE: never say "give me a second", "I will do it", or "I will try later" as a final answer. Either call the tool in this same turn or say what blocks you.
package/src/mcp/index.js CHANGED
@@ -95,7 +95,7 @@ server.tool(
95
95
  {
96
96
  slug: z.string().describe("Agent slug"),
97
97
  prompt: z.string().describe("Prompt / task for the agent"),
98
- runtime: z.string().optional().describe("Runtime: claude-code | codex (default: claude-code)"),
98
+ runtime: z.string().optional().describe("Runtime: claude-code | codex | opencode | aider | cursor-agent | gemini-cli | qwen-code (default: claude-code)"),
99
99
  },
100
100
  async ({ slug, prompt, runtime }) => {
101
101
  const proj = await resolveProject();