@agentprojectcontext/apx 1.10.3 → 1.10.4

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
@@ -113,10 +113,14 @@ can distinguish Telegram users from APX agents and future subagents.
113
113
  | Runtime | Description |
114
114
  |---------|-------------|
115
115
  | `claude-code` | Spawns Claude Code CLI with the agent's system prompt injected |
116
- | `codex` | OpenAI Codex CLI |
116
+ | `codex` | OpenAI Codex CLI via non-interactive `codex exec --sandbox workspace-write --skip-git-repo-check` |
117
117
  | `opencode` | OpenCode CLI |
118
118
  | `aider` | Aider CLI |
119
119
 
120
+ Global APX skill installation also writes named helper skills for `codex-cli`, `claude-code`,
121
+ `opencode-cli`, and `openrouter`. They are intentionally narrow and should activate only when those
122
+ tools/providers are explicitly mentioned.
123
+
120
124
  ## Engines (for `apx exec`)
121
125
 
122
126
  Configured in `~/.apx/config.json`:
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agentprojectcontext/apx",
3
- "version": "1.10.3",
3
+ "version": "1.10.4",
4
4
  "description": "APX — unified CLI + daemon for the Agent Project Context (APC) standard.",
5
5
  "publishConfig": {
6
6
  "access": "public"
@@ -32,10 +32,12 @@ export async function cmdSys(args) {
32
32
  hasStarted: false,
33
33
  sessionTitle: "",
34
34
  usage: { input: 0, output: 0, percent: 0 },
35
+ chatScrollOffset: 0,
35
36
  transcript: [],
36
37
  };
37
38
 
38
39
  const previousMessages = [];
40
+ const pendingPrompts = [];
39
41
  let restored = false;
40
42
  let isRequesting = false;
41
43
 
@@ -74,8 +76,6 @@ export async function cmdSys(args) {
74
76
  renderScreen();
75
77
 
76
78
  process.stdin.on("keypress", async (str, key) => {
77
- if (isRequesting) return;
78
-
79
79
  if (key.ctrl && key.name === "c") {
80
80
  close();
81
81
  }
@@ -102,9 +102,16 @@ export async function cmdSys(args) {
102
102
  return;
103
103
  }
104
104
 
105
+ if (handleScrollKey(key, state, renderScreen)) return;
106
+
105
107
  if (isReturnKey(key)) {
108
+ if (isRequesting) {
109
+ queuePrompt(state, pendingPrompts, renderScreen);
110
+ return;
111
+ }
112
+
106
113
  isRequesting = true;
107
- await submitPrompt(pid, state, previousMessages, renderScreen, close);
114
+ await submitPromptQueue(pid, state, previousMessages, pendingPrompts, renderScreen, close);
108
115
  isRequesting = false;
109
116
  return;
110
117
  }
@@ -117,6 +124,37 @@ export function isReturnKey(key) {
117
124
  return key?.name === "return" || key?.name === "enter";
118
125
  }
119
126
 
127
+ export function handleScrollKey(key, state, renderScreen) {
128
+ if (!state.hasStarted || !key) return false;
129
+ const pageSize = key.name === "pageup" || key.name === "pagedown" ? 8 : 3;
130
+
131
+ if (key.name === "pageup" || key.name === "up" || (key.ctrl && key.name === "up")) {
132
+ state.chatScrollOffset = Math.min(100000, (state.chatScrollOffset || 0) + pageSize);
133
+ renderScreen();
134
+ return true;
135
+ }
136
+
137
+ if (key.name === "pagedown" || key.name === "down" || (key.ctrl && key.name === "down")) {
138
+ state.chatScrollOffset = Math.max(0, (state.chatScrollOffset || 0) - pageSize);
139
+ renderScreen();
140
+ return true;
141
+ }
142
+
143
+ if (key.meta && key.name === "up") {
144
+ state.chatScrollOffset = Math.min(100000, (state.chatScrollOffset || 0) + 20);
145
+ renderScreen();
146
+ return true;
147
+ }
148
+
149
+ if (key.meta && key.name === "down") {
150
+ state.chatScrollOffset = 0;
151
+ renderScreen();
152
+ return true;
153
+ }
154
+
155
+ return false;
156
+ }
157
+
120
158
  async function handlePaletteKey(key, cfg, state, renderScreen, close) {
121
159
  if (key.name === "up") {
122
160
  state.paletteSelection = Math.max(0, state.paletteSelection - 1);
@@ -276,18 +314,46 @@ export function handleEditingKey(str, key, state, renderScreen) {
276
314
  return false;
277
315
  }
278
316
 
279
- async function submitPrompt(pid, state, previousMessages, renderScreen, close) {
317
+ function queuePrompt(state, pendingPrompts, renderScreen) {
280
318
  const text = state.inputText.trim();
281
319
  if (!text) return;
282
- if (text.toLowerCase() === "exit" || text.toLowerCase() === "quit") {
320
+
321
+ state.hasStarted = true;
322
+ state.inputText = "";
323
+ state.cursorIndex = 0;
324
+ state.chatScrollOffset = 0;
325
+
326
+ const item = { type: "user", text, meta: "queued" };
327
+ pendingPrompts.push({ text, item });
328
+ state.transcript.push(item);
329
+ renderScreen();
330
+ }
331
+
332
+ async function submitPromptQueue(pid, state, previousMessages, pendingPrompts, renderScreen, close) {
333
+ const firstText = state.inputText.trim();
334
+ if (!firstText) return;
335
+ if (firstText.toLowerCase() === "exit" || firstText.toLowerCase() === "quit") {
283
336
  close();
284
337
  }
285
338
 
286
339
  state.hasStarted = true;
287
340
  state.inputText = "";
288
341
  state.cursorIndex = 0;
289
- state.transcript.push({ type: "user", text });
290
- state.transcript.push({ type: "status", text: "Thinking..." });
342
+ state.chatScrollOffset = 0;
343
+
344
+ const firstItem = { type: "user", text: firstText };
345
+ state.transcript.push(firstItem);
346
+ await runPrompt(pid, state, previousMessages, renderScreen, firstText, firstItem);
347
+
348
+ while (pendingPrompts.length > 0) {
349
+ const queued = pendingPrompts.shift();
350
+ delete queued.item.meta;
351
+ await runPrompt(pid, state, previousMessages, renderScreen, queued.text, queued.item);
352
+ }
353
+ }
354
+
355
+ async function runPrompt(pid, state, previousMessages, renderScreen, text, userItem) {
356
+ appendLiveItem(state, { type: "status", text: "Thinking...", active: true });
291
357
  renderScreen();
292
358
 
293
359
  const startTime = Date.now();
@@ -312,29 +378,42 @@ async function submitPrompt(pid, state, previousMessages, renderScreen, close) {
312
378
  result = await http.post(`/projects/${pid}/super-agent/chat`, body);
313
379
  removeStatus(state);
314
380
  for (const trace of result.trace || []) {
315
- state.transcript.push({ type: "tool", trace });
381
+ appendLiveItem(state, { type: "tool", trace });
316
382
  }
317
383
  }
318
384
 
319
385
  completeSuperAgentResult(result, text, startTime, state, previousMessages);
320
386
  } catch (e) {
321
387
  removeStatus(state);
322
- state.transcript.push({ type: "error", text: e.message });
388
+ appendLiveItem(state, { type: "error", text: e.message });
323
389
  }
324
390
 
391
+ if (userItem) delete userItem.meta;
325
392
  renderScreen();
326
393
  }
327
394
 
328
395
  function removeStatus(state) {
329
- const last = state.transcript[state.transcript.length - 1];
330
- if (last?.type === "status") state.transcript.pop();
396
+ for (let i = state.transcript.length - 1; i >= 0; i--) {
397
+ if (state.transcript[i]?.type === "status" && state.transcript[i]?.active) {
398
+ state.transcript.splice(i, 1);
399
+ return;
400
+ }
401
+ }
402
+ }
403
+
404
+ function appendLiveItem(state, item) {
405
+ const queuedIndex = state.transcript.findIndex(
406
+ (entry) => entry?.type === "user" && entry?.meta === "queued"
407
+ );
408
+ if (queuedIndex >= 0) state.transcript.splice(queuedIndex, 0, item);
409
+ else state.transcript.push(item);
331
410
  }
332
411
 
333
412
  function handleProgressEvent(event, state, renderScreen) {
334
413
  if (event.type === "model_start") {
335
- const last = state.transcript[state.transcript.length - 1];
336
- if (last?.type === "status") {
337
- last.text = event.iteration > 1 ? `Thinking... step ${event.iteration}` : "Thinking...";
414
+ const status = [...state.transcript].reverse().find((item) => item?.type === "status" && item?.active);
415
+ if (status) {
416
+ status.text = event.iteration > 1 ? `Thinking... step ${event.iteration}` : "Thinking...";
338
417
  renderScreen();
339
418
  }
340
419
  return;
@@ -342,7 +421,7 @@ function handleProgressEvent(event, state, renderScreen) {
342
421
 
343
422
  if (event.type === "assistant_text" && event.text) {
344
423
  removeStatus(state);
345
- state.transcript.push({
424
+ appendLiveItem(state, {
346
425
  type: "assistant",
347
426
  name: state.activeAgent,
348
427
  text: event.text,
@@ -354,7 +433,7 @@ function handleProgressEvent(event, state, renderScreen) {
354
433
 
355
434
  if (event.type === "tool_start" && event.trace) {
356
435
  removeStatus(state);
357
- state.transcript.push({ type: "tool", trace: event.trace });
436
+ appendLiveItem(state, { type: "tool", trace: event.trace });
358
437
  renderScreen();
359
438
  return;
360
439
  }
@@ -365,7 +444,7 @@ function handleProgressEvent(event, state, renderScreen) {
365
444
  (item) => item.type === "tool" && item.trace?.id && item.trace.id === event.trace.id
366
445
  );
367
446
  if (idx >= 0) state.transcript[idx] = { type: "tool", trace: event.trace };
368
- else state.transcript.push({ type: "tool", trace: event.trace });
447
+ else appendLiveItem(state, { type: "tool", trace: event.trace });
369
448
  renderScreen();
370
449
  }
371
450
  }
@@ -383,7 +462,7 @@ function completeSuperAgentResult(result, userText, startTime, state, previousMe
383
462
  state.usage.output += result.usage?.output_tokens || 0;
384
463
  state.usage.percent = Math.min(99, Math.round((state.usage.input / 200000) * 100));
385
464
 
386
- state.transcript.push({
465
+ appendLiveItem(state, {
387
466
  type: "assistant",
388
467
  name: state.activeAgent,
389
468
  text: result.text,
@@ -275,6 +275,9 @@ function transcriptLines(transcript, width) {
275
275
  for (const chunk of chunks) {
276
276
  addLine(lines, margin + C.primary + "┃" + C.panel + " " + C.text + padAnsi(chunk, inner), C.bg);
277
277
  }
278
+ if (item.meta) {
279
+ addLine(lines, margin + C.primary + "┃" + C.panel + " " + C.muted + padAnsi(item.meta, inner), C.bg);
280
+ }
278
281
  addLine(lines, margin + C.primary + "┃" + C.panel + " " + " ".repeat(inner), C.bg);
279
282
  continue;
280
283
  }
@@ -315,14 +318,22 @@ function transcriptLines(transcript, width) {
315
318
  return lines;
316
319
  }
317
320
 
318
- function renderChat(transcript, chatWidth, height, promptTop) {
321
+ function renderChat(state, chatWidth, height, promptTop) {
319
322
  const maxRows = Math.max(1, promptTop - 1);
320
- const lines = transcriptLines(transcript, chatWidth - 2);
321
- const slice = lines.slice(Math.max(0, lines.length - maxRows));
323
+ const lines = transcriptLines(state.transcript, chatWidth - 2);
324
+ const maxOffset = Math.max(0, lines.length - maxRows);
325
+ const offset = Math.min(Math.max(0, state.chatScrollOffset || 0), maxOffset);
326
+ state.chatScrollOffset = offset;
327
+ const start = Math.max(0, lines.length - maxRows - offset);
328
+ const slice = lines.slice(start, start + maxRows);
322
329
 
323
330
  for (let i = 0; i < slice.length && i < maxRows; i++) {
324
331
  writeAt(i, 0, slice[i].text, chatWidth - 1, slice[i].bg);
325
332
  }
333
+
334
+ if (offset > 0 && maxRows > 1) {
335
+ writeAt(0, 0, C.muted + `↑ ${offset} lines above bottom`, chatWidth - 1, C.bg);
336
+ }
326
337
  }
327
338
 
328
339
  function renderSidebar(state) {
@@ -407,7 +418,7 @@ export function renderTerminalChat(state) {
407
418
  renderLogo(chatWidth, Math.max(1, Math.floor(height / 2) - 8));
408
419
  } else {
409
420
  const prompt = promptGeometry(false, true, chatWidth);
410
- renderChat(state.transcript, chatWidth, height, prompt.top);
421
+ renderChat(state, chatWidth, height, prompt.top);
411
422
  }
412
423
 
413
424
  const cursor = renderPromptBlock(state, chatWidth);
@@ -42,6 +42,22 @@ The output is the agent's full stdout. If it printed `APC_RESULT: <value>`, that
42
42
  apx exec <slug> "<prompt>"
43
43
  ```
44
44
 
45
+ ## Command accuracy
46
+
47
+ Do not invent APX subcommands. Before telling another runtime to call APX, verify the exact CLI
48
+ form with `apx --help` or `apx <command> --help`.
49
+
50
+ Known Telegram form:
51
+
52
+ ```bash
53
+ apx telegram status
54
+ apx telegram send "message"
55
+ apx telegram send "message" --chat 123456
56
+ ```
57
+
58
+ Do not use guessed aliases such as `apx send-telegram` or `apx telegram "message"` unless current
59
+ `apx --help` shows that exact form.
60
+
45
61
  ## MCP tools
46
62
 
47
63
  MCPs declared in `.apc/mcps.json` are proxied through the APX daemon. Use `apx mcp` only for MCPs registered there — not for MCPs that are already running locally in your IDE session.
@@ -0,0 +1,68 @@
1
+ ---
2
+ name: claude-code
3
+ description: "Activate ONLY when the user explicitly mentions Claude Code, Claude CLI, claude command, Anthropic Claude Code, installing Claude Code, using Claude Code, or APX runtime claude-code. Do not activate for generic Claude model discussion."
4
+ homepage: https://docs.anthropic.com/en/docs/claude-code
5
+ ---
6
+ # Claude Code CLI
7
+
8
+ Use this skill only for Claude Code CLI install, auth, usage, or APX runtime dispatch.
9
+
10
+ ## Verify before acting
11
+
12
+ Check the local CLI first:
13
+
14
+ ```bash
15
+ claude --version
16
+ claude --help
17
+ ```
18
+
19
+ Do not invent flags. If a command is uncertain, inspect help for the exact subcommand before
20
+ running it.
21
+
22
+ ## Install
23
+
24
+ Common install/update path:
25
+
26
+ ```bash
27
+ npm install -g @anthropic-ai/claude-code
28
+ claude --version
29
+ ```
30
+
31
+ Claude Code also exposes:
32
+
33
+ ```bash
34
+ claude install
35
+ claude update
36
+ claude auth
37
+ ```
38
+
39
+ Use `claude --help` to confirm current syntax.
40
+
41
+ ## Non-interactive use
42
+
43
+ Prefer headless print mode:
44
+
45
+ ```bash
46
+ claude -p "task" --output-format json
47
+ claude -p "task" --append-system-prompt "system instructions" --output-format json
48
+ ```
49
+
50
+ For high-trust automation in an already sandboxed environment:
51
+
52
+ ```bash
53
+ claude -p "task" --permission-mode bypassPermissions --output-format json
54
+ ```
55
+
56
+ ## APX runtime
57
+
58
+ Run a project agent through Claude Code:
59
+
60
+ ```bash
61
+ apx run <agent> --runtime claude-code "task"
62
+ ```
63
+
64
+ If the task needs Telegram, tell Claude Code the exact APX command:
65
+
66
+ ```bash
67
+ apx telegram send "message"
68
+ ```
@@ -0,0 +1,75 @@
1
+ ---
2
+ name: codex-cli
3
+ description: "Activate ONLY when the user explicitly mentions Codex CLI, OpenAI Codex, @openai/codex, codex command, codex exec, installing Codex, using Codex, ~/.codex, or APX runtime codex."
4
+ homepage: https://developers.openai.com/codex
5
+ ---
6
+ # Codex CLI
7
+
8
+ Use this skill only for Codex CLI install, auth, usage, or APX runtime dispatch.
9
+
10
+ ## Verify before acting
11
+
12
+ Check local CLI and exact flags first:
13
+
14
+ ```bash
15
+ codex --version
16
+ codex --help
17
+ codex exec --help
18
+ ```
19
+
20
+ Do not invent flags. Current Codex CLI may reject older flags such as `--approval-mode` or
21
+ `--full-auto`.
22
+
23
+ ## Install
24
+
25
+ Common install/update path:
26
+
27
+ ```bash
28
+ npm install -g @openai/codex
29
+ codex --version
30
+ ```
31
+
32
+ Codex also exposes:
33
+
34
+ ```bash
35
+ codex login
36
+ codex update
37
+ ```
38
+
39
+ Auth check:
40
+
41
+ ```bash
42
+ test -f ~/.codex/auth.json && echo "codex auth present"
43
+ ```
44
+
45
+ ## Non-interactive use
46
+
47
+ Use `exec`, not interactive TUI, for automation:
48
+
49
+ ```bash
50
+ codex exec --sandbox workspace-write --skip-git-repo-check "task"
51
+ ```
52
+
53
+ Useful options:
54
+
55
+ ```bash
56
+ codex exec --sandbox workspace-write --skip-git-repo-check --output-last-message /tmp/codex-last.txt "task"
57
+ codex exec --json --sandbox workspace-write --skip-git-repo-check "task"
58
+ ```
59
+
60
+ `--skip-git-repo-check` matters for APX default runtime dirs such as `~/.apx/projects/default`,
61
+ which may not be Git repositories.
62
+
63
+ ## APX runtime
64
+
65
+ Run a project agent through Codex:
66
+
67
+ ```bash
68
+ apx run <agent> --runtime codex "task"
69
+ ```
70
+
71
+ If the task needs Telegram, tell Codex the exact APX command:
72
+
73
+ ```bash
74
+ apx telegram send "message"
75
+ ```
@@ -0,0 +1,59 @@
1
+ ---
2
+ name: opencode-cli
3
+ description: "Activate ONLY when the user explicitly mentions OpenCode, opencode command, installing OpenCode, using OpenCode, OpenCode provider setup, or APX runtime opencode."
4
+ homepage: https://opencode.ai/docs
5
+ ---
6
+ # OpenCode CLI
7
+
8
+ Use this skill only for OpenCode CLI install, auth/provider setup, usage, or APX runtime dispatch.
9
+
10
+ ## Verify before acting
11
+
12
+ Check local CLI and exact flags first:
13
+
14
+ ```bash
15
+ opencode --version
16
+ opencode --help
17
+ opencode run --help
18
+ ```
19
+
20
+ Do not invent flags. Inspect help for the exact subcommand before running uncertain commands.
21
+
22
+ ## Install
23
+
24
+ Use the official install method for the target machine, then verify:
25
+
26
+ ```bash
27
+ opencode --version
28
+ ```
29
+
30
+ Provider/auth management:
31
+
32
+ ```bash
33
+ opencode providers
34
+ opencode models
35
+ ```
36
+
37
+ ## Non-interactive use
38
+
39
+ Use headless run:
40
+
41
+ ```bash
42
+ opencode run "task"
43
+ opencode run --model provider/model "task"
44
+ opencode run --dangerously-skip-permissions "task"
45
+ ```
46
+
47
+ ## APX runtime
48
+
49
+ Run a project agent through OpenCode:
50
+
51
+ ```bash
52
+ apx run <agent> --runtime opencode "task"
53
+ ```
54
+
55
+ If the task needs Telegram, tell OpenCode the exact APX command:
56
+
57
+ ```bash
58
+ apx telegram send "message"
59
+ ```
@@ -0,0 +1,54 @@
1
+ ---
2
+ name: openrouter
3
+ description: "Activate ONLY when the user explicitly mentions OpenRouter, OPENROUTER_API_KEY, OpenRouter models, installing OpenRouter provider config, or using OpenRouter with APX, OpenCode, LiteLLM, or an OpenAI-compatible client."
4
+ homepage: https://openrouter.ai/docs
5
+ ---
6
+ # OpenRouter
7
+
8
+ Use this skill only for OpenRouter install/config, model listing, or usage through APX/OpenCode or
9
+ OpenAI-compatible clients.
10
+
11
+ ## Verify before acting
12
+
13
+ OpenRouter is an API/provider, not a local coding runtime by itself. First identify which client
14
+ will use it: APX engine, OpenCode provider, LiteLLM, OpenAI SDK, or another OpenAI-compatible tool.
15
+
16
+ Do not expose keys. Check only presence:
17
+
18
+ ```bash
19
+ test -n "$OPENROUTER_API_KEY" && echo "OPENROUTER_API_KEY present"
20
+ ```
21
+
22
+ ## OpenAI-compatible base URL
23
+
24
+ Typical API settings:
25
+
26
+ ```bash
27
+ OPENAI_BASE_URL=https://openrouter.ai/api/v1
28
+ OPENROUTER_API_KEY=...
29
+ ```
30
+
31
+ Use the selected client's current docs/help before writing config.
32
+
33
+ ## APX guidance
34
+
35
+ If configuring APX engine/provider, inspect current config schema first:
36
+
37
+ ```bash
38
+ apx config --help
39
+ apx status
40
+ ```
41
+
42
+ Then update only non-secret project-safe settings. Keep API keys in user config or environment, not
43
+ in `.apc/` or git.
44
+
45
+ ## OpenCode guidance
46
+
47
+ If using OpenRouter via OpenCode, inspect provider commands first:
48
+
49
+ ```bash
50
+ opencode providers
51
+ opencode models
52
+ ```
53
+
54
+ Then configure OpenRouter through OpenCode's current provider flow.
@@ -87,7 +87,7 @@ function buildSkillMd(content) {
87
87
  const frontmatter = [
88
88
  "---",
89
89
  "name: apx",
90
- "description: APX CLI skill. Activate when: user asks to run or coordinate agents, use MCP tools from .apc/mcps.json, install agents from a team workspace, or explicitly mentions apx commands. Do NOT activate just because .apc/ exists — that is handled by the apc-context skill. Activate on: 'apx run', 'apx exec', 'run an agent', 'coordinate agents', 'MCP not working', 'install agent', 'team agents', 'apx memory', 'daemon'.",
90
+ "description: \"APX CLI skill. Activate when: user asks to run or coordinate agents, use MCP tools from .apc/mcps.json, install agents from a team workspace, or explicitly mentions apx commands. Do NOT activate just because .apc/ exists — that is handled by the apc-context skill. Activate on: 'apx run', 'apx exec', 'run an agent', 'coordinate agents', 'MCP not working', 'install agent', 'team agents', 'apx memory', 'daemon'.\"",
91
91
  "homepage: https://github.com/agentprojectcontext/apx",
92
92
  "---",
93
93
  "",
@@ -95,6 +95,19 @@ function buildSkillMd(content) {
95
95
  return frontmatter + content;
96
96
  }
97
97
 
98
+ function readRuntimeSkillFiles() {
99
+ const skillsDir = path.join(__dirname, "runtime-skills");
100
+ if (!fs.existsSync(skillsDir)) return [];
101
+
102
+ return fs.readdirSync(skillsDir)
103
+ .filter((name) => name.endsWith(".md"))
104
+ .sort()
105
+ .map((name) => ({
106
+ slug: path.basename(name, ".md"),
107
+ md: fs.readFileSync(path.join(skillsDir, name), "utf8").trim(),
108
+ }));
109
+ }
110
+
98
111
  // Install APX + APC context skills into IDE rule files. Returns an array of result objects.
99
112
  // targetIds: array of target ids to install; null = all project targets.
100
113
  export function installIdeSkills(root, targetIds = null) {
@@ -159,6 +172,7 @@ export function installGlobalSkills() {
159
172
  skills.push({ slug: "apx", md: buildSkillMd(fs.readFileSync(apxSrc, "utf8").trim()) });
160
173
  if (fs.existsSync(apcSrc))
161
174
  skills.push({ slug: "apc-context", md: buildApcContextSkillMd(fs.readFileSync(apcSrc, "utf8").trim()) });
175
+ skills.push(...readRuntimeSkillFiles());
162
176
 
163
177
  for (const base of GLOBAL_SKILL_DIRS) {
164
178
  for (const { slug, md } of skills) {
@@ -1,5 +1,5 @@
1
1
  // OpenAI Codex CLI runtime adapter.
2
- // codex exec "<prompt>"
2
+ // codex exec --sandbox workspace-write --skip-git-repo-check "<prompt>"
3
3
  // System prompt is prepended to the prompt body since Codex doesn't have a
4
4
  // dedicated --system flag in `exec` mode.
5
5
  // Reference: https://github.com/openai/codex
@@ -15,7 +15,7 @@ export default {
15
15
  const fullPrompt = system ? `${system}\n\n---\n\n${prompt}` : prompt;
16
16
  const r = await runProcess({
17
17
  command: "codex",
18
- args: ["exec", fullPrompt],
18
+ args: ["exec", "--sandbox", "workspace-write", "--skip-git-repo-check", fullPrompt],
19
19
  cwd,
20
20
  env,
21
21
  timeoutMs,