@technomoron/agent-run 0.99.12 → 0.99.14

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/CHANGES CHANGED
@@ -1,8 +1,13 @@
1
1
  CHANGES
2
2
  =======
3
3
 
4
- Unreleased (2026-04-24)
5
- -----------------------
4
+ Version 0.99.14 (2026-04-30)
5
+ ----------------------------
6
+ * Add `--show` for Codex and Claude runs to print the tool-specific source templates/includes and generated files without launching the underlying tool.
7
+
8
+ Version 0.99.13 (2026-04-27)
9
+ ----------------------------
10
+ * Render each profile's generated files and runtime state under `live/`, leaving the profile root for source config and templates.
6
11
 
7
12
  Version 0.99.12 (2026-04-27)
8
13
  ----------------------------
package/dist/agent-run.js CHANGED
@@ -22,28 +22,13 @@ const CONFIG_DIR_ENV = 'AGENT_CONFIG_DIR';
22
22
  const VERBOSE_ENV = 'AGENT_RUN_VERBOSE';
23
23
  const MANIFEST_FILE_NAME = 'agent-run.jsonc';
24
24
  const LOCAL_TEMPLATE_FILE_NAME = 'local.md.njk';
25
+ const LIVE_DIR_NAME = 'live';
25
26
  const PACKAGE_VERSION = '0.99.10';
26
27
  const UNEXPANDED_TEMPLATE_RE = /\{\{[^}]+\}\}|\{%[^%]+%\}/;
27
28
  const agentRunEnvCache = new Map();
28
29
  const GENERATED_GITIGNORE_ENTRIES = [
29
- '# Generated agent-run files',
30
- '**/AGENTS.md',
31
- '**/CLAUDE.md',
32
- '**/GEMINI.md',
33
- '**/config.toml',
34
- '',
35
- '# Generated native agent homes',
36
- '**/.agents/',
37
- '**/.claude/',
38
- '**/.codex/',
39
- '',
40
- '# Generated runtime files',
41
- '**/bin/',
42
- '**/reviews/',
43
- '**/memories/',
44
- '',
45
- '# Generated review reports',
46
- '**/REVIEW-*.md',
30
+ '# Generated agent-run live profiles',
31
+ '**/live/',
47
32
  '',
48
33
  '# Optional generated caches',
49
34
  '**/.agent-run-cache/'
@@ -217,6 +202,7 @@ function parseRunCommand(command, inputArgs) {
217
202
  none: false,
218
203
  create: false,
219
204
  local: false,
205
+ show: false,
220
206
  codexSandboxMode: null,
221
207
  codexNetwork: false
222
208
  };
@@ -243,6 +229,10 @@ function parseRunCommand(command, inputArgs) {
243
229
  wrapperArgs.local = true;
244
230
  continue;
245
231
  }
232
+ if (arg === '--show') {
233
+ wrapperArgs.show = true;
234
+ continue;
235
+ }
246
236
  if (arg === '--danger') {
247
237
  if (command !== 'codex') {
248
238
  fail('--danger is only supported for agent-run codex');
@@ -417,9 +407,9 @@ function renderHelp(topic) {
417
407
  ' agent-run --init [config-root]',
418
408
  '',
419
409
  'Commands:',
420
- ' codex [--none] [--create] [--local] [--danger|--sandboxed] [--network] [args...]',
410
+ ' codex [--none] [--create] [--local] [--show] [--danger|--sandboxed] [--network] [args...]',
421
411
  ' Run codex with generated private config',
422
- ' claude [--none] [--create] [--local] [args...]',
412
+ ' claude [--none] [--create] [--local] [--show] [args...]',
423
413
  ' Run claude with generated private config',
424
414
  ' check [--all] [path] Validate generated profile output',
425
415
  ' init [path] Create profile source files and render output',
@@ -434,8 +424,11 @@ function renderHelp(topic) {
434
424
  ' --config-root DIR Override the agent-config root',
435
425
  ' --init [DIR] Copy the packaged starter config root to DIR (default ~/.agent-config)',
436
426
  '',
437
- 'Codex wrapper options:',
427
+ 'Run wrapper options:',
438
428
  ' --local Warn about local AI files instead of failing',
429
+ ' --show Show read/include and generated files without running the tool',
430
+ '',
431
+ 'Codex wrapper options:',
439
432
  ' --danger Run Codex with no sandbox: -a never -s danger-full-access (default)',
440
433
  ' --sandboxed Run Codex with workspace-write sandbox',
441
434
  ' --network Enable network for --sandboxed via config override',
@@ -489,30 +482,41 @@ function normalizeCommandName(value) {
489
482
  }
490
483
  function runTool(parsed) {
491
484
  const { args, command, wrapperArgs } = parsed;
492
- const realBinary = findRealBinary(command);
493
- const permissionArgs = getPermissionArgs(command);
494
485
  const projectRoot = findProjectRoot(process.cwd());
495
486
  verbose(`run ${command}: cwd=${process.cwd()} projectRoot=${projectRoot}`);
487
+ if (wrapperArgs.show && wrapperArgs.none) {
488
+ fail('--show cannot be combined with --none');
489
+ }
490
+ if (wrapperArgs.show && isIgnoredDir(projectRoot)) {
491
+ fail(`cannot show generated ${command} files for ignored project: ${projectRoot}`);
492
+ }
496
493
  if (wrapperArgs.none || isIgnoredDir(projectRoot)) {
494
+ const realBinary = findRealBinary(command);
495
+ const permissionArgs = getPermissionArgs(command);
497
496
  verbose(`wrapper bypassed for ${command}${wrapperArgs.none ? ' via --none' : ' because project is ignored'}`);
498
497
  execTool(realBinary, [...permissionArgs, ...args]);
499
498
  return;
500
499
  }
501
500
  const profileResult = resolveProfileResult(projectRoot);
502
- const excludedDir = profileResult.profile === null ? null : resolveAgentDir(projectRoot);
503
- const localAiFiles = findLocalAiFiles(projectRoot, excludedDir);
504
- if (localAiFiles.length > 0) {
505
- if (!wrapperArgs.local) {
506
- failForLocalAiFiles(command, projectRoot, localAiFiles);
507
- }
508
- warnForLocalAiFiles(command, projectRoot, localAiFiles);
509
- }
510
501
  if (profileResult.profile === null) {
511
502
  fail(profileResult.reason);
512
503
  }
513
504
  const profile = profileResult.profile;
514
505
  const configRoot = defaultConfigRoot(projectRoot);
515
506
  const agentDir = resolveAgentDir(projectRoot);
507
+ if (wrapperArgs.show) {
508
+ showToolProfile(command, projectRoot, agentDir);
509
+ return;
510
+ }
511
+ const localAiFiles = findLocalAiFiles(projectRoot, agentDir);
512
+ if (localAiFiles.length > 0) {
513
+ if (!wrapperArgs.local) {
514
+ failForLocalAiFiles(command, projectRoot, localAiFiles);
515
+ }
516
+ warnForLocalAiFiles(command, projectRoot, localAiFiles);
517
+ }
518
+ const realBinary = findRealBinary(command);
519
+ const permissionArgs = getPermissionArgs(command);
516
520
  if (wrapperArgs.create) {
517
521
  runInit({ command: 'init', targetPath: projectRoot });
518
522
  }
@@ -524,6 +528,31 @@ function runTool(parsed) {
524
528
  }
525
529
  runClaude(realBinary, permissionArgs, agentDir, configRoot, args, projectRoot, wrapperArgs);
526
530
  }
531
+ function showToolProfile(command, projectRoot, agentDir) {
532
+ const trace = { sourceFiles: new Set() };
533
+ const rendered = renderProfile(projectRoot, agentDir, true, command, trace);
534
+ const generatedFiles = uniqueSorted(rendered.files.map((file) => file.path));
535
+ const sourceFiles = uniqueSorted([...trace.sourceFiles]);
536
+ process.stdout.write([
537
+ `Agent: ${command}`,
538
+ `Profile: ${rendered.profile}`,
539
+ `Project root: ${projectRoot}`,
540
+ `Profile dir: ${agentDir}`,
541
+ '',
542
+ 'Reads/includes:',
543
+ ...formatPathList(sourceFiles),
544
+ '',
545
+ 'Generates:',
546
+ ...formatPathList(generatedFiles),
547
+ ''
548
+ ].join('\n'));
549
+ }
550
+ function uniqueSorted(values) {
551
+ return [...new Set(values.map((value) => path.resolve(value)))].sort((a, b) => a.localeCompare(b));
552
+ }
553
+ function formatPathList(paths) {
554
+ return paths.length === 0 ? [' (none)'] : paths.map((entry) => ` ${entry}`);
555
+ }
527
556
  function runInit(parsed) {
528
557
  const projectRoot = findProjectRoot(parsed.targetPath);
529
558
  verbose(`init target=${parsed.targetPath} projectRoot=${projectRoot}`);
@@ -670,7 +699,8 @@ function runCheck(parsed) {
670
699
  }
671
700
  function printUpdateSummary(rendered) {
672
701
  process.stdout.write(`OK profile ${rendered.profile}\n`);
673
- process.stdout.write(`Agent dir: ${rendered.agentDir}\n`);
702
+ process.stdout.write(`Profile dir: ${rendered.agentDir}\n`);
703
+ process.stdout.write(`Live dir: ${rendered.context.paths.liveDir}\n`);
674
704
  process.stdout.write(`Generated files: ${rendered.files.length}\n`);
675
705
  process.stdout.write(`Installed skills: ${rendered.skills.map((skill) => skill.name).join(', ') || '(none)'}\n`);
676
706
  }
@@ -873,7 +903,7 @@ function createDefaultLocalFile(agentDir, profile) {
873
903
  function ensureProfileOverridesDir(agentDir) {
874
904
  fs.mkdirSync(path.join(agentDir, 'overrides'), { recursive: true });
875
905
  }
876
- function loadManifest(_configRoot, agentDir, profile) {
906
+ function loadManifest(_configRoot, agentDir, profile, trace) {
877
907
  const manifestPath = path.join(agentDir, MANIFEST_FILE_NAME);
878
908
  if (!fs.existsSync(manifestPath)) {
879
909
  const manifest = defaultManifest(profile);
@@ -893,6 +923,7 @@ function loadManifest(_configRoot, agentDir, profile) {
893
923
  }
894
924
  return manifest;
895
925
  }
926
+ trace?.sourceFiles.add(manifestPath);
896
927
  const text = fs.readFileSync(manifestPath, 'utf8');
897
928
  const errors = [];
898
929
  const parsed = (0, jsonc_parser_1.parse)(text, errors, { allowTrailingComma: true });
@@ -992,29 +1023,33 @@ function createNunjucksEnv(configRoot) {
992
1023
  throwOnUndefined: true
993
1024
  });
994
1025
  }
995
- function buildRenderContext(projectRoot, agentDir, configRoot, manifest, env) {
1026
+ function buildRenderContext(projectRoot, profileDir, configRoot, manifest, env) {
996
1027
  const date = localDateString();
1028
+ const liveDir = path.join(profileDir, LIVE_DIR_NAME);
997
1029
  const baseContext = {
998
1030
  profile: manifest.profile,
999
1031
  kind: manifest.kind,
1000
1032
  projectRoot,
1001
- agentDir,
1033
+ agentDir: liveDir,
1034
+ profileDir,
1002
1035
  configRoot,
1003
1036
  date,
1004
1037
  checks: manifest.checks,
1005
1038
  guardrails: manifest.guardrails
1006
1039
  };
1007
1040
  const paths = {
1041
+ profileDir,
1042
+ liveDir,
1008
1043
  changesFile: resolveRuntimePath(configRoot, manifest.paths.changesFile, env, baseContext),
1009
1044
  reviewDir: resolveRuntimePath(configRoot, manifest.paths.reviewDir, env, baseContext),
1010
1045
  reviewFile: resolveRuntimePath(configRoot, manifest.paths.reviewFile, env, baseContext),
1011
1046
  memoriesDir: resolveRuntimePath(configRoot, manifest.paths.memoriesDir, env, baseContext),
1012
1047
  globalMemoryDir: globalMemoryDir(configRoot),
1013
1048
  codexHomeDir: path.join(resolveRuntimePath(configRoot, manifest.paths.memoriesDir, env, baseContext), 'codex-home'),
1014
- overridesDir: path.join(agentDir, 'overrides'),
1015
- codexSkillsDir: path.join(agentDir, '.agents', 'skills'),
1016
- claudeSkillsDir: path.join(agentDir, '.claude', 'skills'),
1017
- binDir: path.join(agentDir, 'bin')
1049
+ overridesDir: path.join(profileDir, 'overrides'),
1050
+ codexSkillsDir: path.join(liveDir, '.agents', 'skills'),
1051
+ claudeSkillsDir: path.join(liveDir, '.claude', 'skills'),
1052
+ binDir: path.join(liveDir, 'bin')
1018
1053
  };
1019
1054
  return {
1020
1055
  ...baseContext,
@@ -1047,19 +1082,48 @@ function resolveRuntimePath(configRoot, pathTemplate, env, context) {
1047
1082
  const rendered = renderInlineTemplate(env, pathTemplate, context);
1048
1083
  return path.isAbsolute(rendered) ? path.resolve(rendered) : path.resolve(configRoot, rendered);
1049
1084
  }
1050
- function renderTemplateFile(env, configRoot, templatePath, context) {
1085
+ function renderTemplateFile(env, configRoot, templatePath, context, trace) {
1051
1086
  const resolvedPath = resolveConfigPath(configRoot, templatePath, context);
1052
1087
  if (!fs.existsSync(resolvedPath)) {
1053
1088
  throw new Error(`missing template: ${resolvedPath}`);
1054
1089
  }
1055
1090
  const relativePath = path.relative(configRoot, resolvedPath).replace(/\\/g, '/');
1056
1091
  let content = fs.readFileSync(resolvedPath, 'utf8');
1092
+ traceTemplateSource(configRoot, resolvedPath, content, context, trace);
1057
1093
  if (path.basename(resolvedPath) === 'AGENTS-MODS.md') {
1058
- content = renderLegacyAgentsMods(resolvedPath);
1094
+ content = renderLegacyAgentsMods(resolvedPath, [], trace);
1059
1095
  return renderInlineTemplate(env, content, context);
1060
1096
  }
1061
1097
  return env.render(relativePath, context);
1062
1098
  }
1099
+ function traceTemplateSource(configRoot, sourcePath, content, context, trace, stack = []) {
1100
+ if (trace === undefined) {
1101
+ return;
1102
+ }
1103
+ const resolvedSource = path.resolve(sourcePath);
1104
+ trace.sourceFiles.add(resolvedSource);
1105
+ if (stack.includes(resolvedSource)) {
1106
+ return;
1107
+ }
1108
+ const nextStack = [...stack, resolvedSource];
1109
+ const includeRe = /{%\s*(?:include|extends|import)\s+["']([^"']+)["']|{%\s*from\s+["']([^"']+)["']/g;
1110
+ for (;;) {
1111
+ const match = includeRe.exec(content);
1112
+ if (match === null) {
1113
+ break;
1114
+ }
1115
+ const includePath = match[1] ?? match[2];
1116
+ if (!includePath) {
1117
+ continue;
1118
+ }
1119
+ const includedPath = resolveConfigPath(configRoot, includePath, context);
1120
+ if (!fs.existsSync(includedPath)) {
1121
+ continue;
1122
+ }
1123
+ const includedContent = fs.readFileSync(includedPath, 'utf8');
1124
+ traceTemplateSource(configRoot, includedPath, includedContent, context, trace, nextStack);
1125
+ }
1126
+ }
1063
1127
  function renderInlineTemplate(env, source, context) {
1064
1128
  return env.renderString(source, context);
1065
1129
  }
@@ -1100,11 +1164,11 @@ function copySkeletonTree(sourceDir, targetDir) {
1100
1164
  fs.copyFileSync(sourcePath, targetPath);
1101
1165
  }
1102
1166
  }
1103
- function renderProfile(projectRoot, agentDir, checkOnly = false) {
1167
+ function renderProfile(projectRoot, agentDir, checkOnly = false, targetTool = null, trace) {
1104
1168
  const configRoot = defaultConfigRoot(projectRoot);
1105
1169
  const profile = resolveProfile(projectRoot);
1106
1170
  const env = createNunjucksEnv(configRoot);
1107
- const manifest = normalizeManifest(loadManifest(configRoot, agentDir, profile), profile);
1171
+ const manifest = normalizeManifest(loadManifest(configRoot, agentDir, profile, trace), profile);
1108
1172
  if (manifest.profile !== profile) {
1109
1173
  const parsed = parseProfile(manifest.profile, `${path.join(agentDir, MANIFEST_FILE_NAME)} profile`);
1110
1174
  if (parsed.profile === null) {
@@ -1115,7 +1179,7 @@ function renderProfile(projectRoot, agentDir, checkOnly = false) {
1115
1179
  ensureConfigRootGitignore(configRoot);
1116
1180
  }
1117
1181
  const context = buildRenderContext(projectRoot, agentDir, configRoot, manifest, env);
1118
- const sections = [renderTemplateFile(env, configRoot, manifest.agent.base, context)];
1182
+ const sections = [renderTemplateFile(env, configRoot, manifest.agent.base, context, trace)];
1119
1183
  for (const include of manifest.agent.includes) {
1120
1184
  const includePath = resolveConfigPath(configRoot, include, context);
1121
1185
  if (!fs.existsSync(includePath)) {
@@ -1124,23 +1188,31 @@ function renderProfile(projectRoot, agentDir, checkOnly = false) {
1124
1188
  }
1125
1189
  throw new Error(`missing template: ${includePath}`);
1126
1190
  }
1127
- sections.push(renderTemplateFile(env, configRoot, include, context));
1191
+ sections.push(renderTemplateFile(env, configRoot, include, context, trace));
1128
1192
  }
1129
1193
  context.renderedAgentSections = sections.map((section, index) => {
1130
1194
  const label = index === 0 ? manifest.agent.base : manifest.agent.includes[index - 1] ?? `section ${index}`;
1131
1195
  assertNoUnexpandedTemplateVars(label, section);
1132
1196
  return section.trimEnd();
1133
1197
  });
1134
- context.skills = renderSkills(env, configRoot, manifest, context);
1198
+ context.skills = renderSkills(env, configRoot, manifest, context, trace);
1135
1199
  const files = [];
1136
- const agentsContent = renderToolInstructions('AGENTS.md', env, configRoot, context, false);
1137
- const claudeContent = renderToolInstructions('CLAUDE.md', env, configRoot, context, true);
1138
- files.push({ path: path.join(agentDir, 'AGENTS.md'), content: agentsContent });
1139
- files.push({ path: path.join(agentDir, 'CLAUDE.md'), content: claudeContent });
1140
- files.push({ path: path.join(agentDir, '.claude', 'CLAUDE.md'), content: claudeContent });
1141
- files.push({ path: path.join(agentDir, 'config.toml'), content: renderCodexConfig(env, configRoot, context) });
1142
- files.push({ path: path.join(agentDir, '.claude', 'agent-run-settings.json'), content: renderClaudeSettings(env, configRoot, context) });
1143
- files.push(...renderNativeSkillFiles(context));
1200
+ if (targetTool === null || targetTool === 'codex') {
1201
+ const agentsContent = renderToolInstructions('AGENTS.md', env, configRoot, context, false, trace);
1202
+ files.push({ path: path.join(context.paths.liveDir, 'AGENTS.md'), content: agentsContent });
1203
+ files.push({ path: path.join(context.paths.liveDir, 'config.toml'), content: renderCodexConfig(env, configRoot, context, trace) });
1204
+ files.push(...renderNativeSkillFiles(context, 'codex'));
1205
+ }
1206
+ if (targetTool === null || targetTool === 'claude') {
1207
+ const claudeContent = renderToolInstructions('CLAUDE.md', env, configRoot, context, true, trace);
1208
+ files.push({ path: path.join(context.paths.liveDir, 'CLAUDE.md'), content: claudeContent });
1209
+ files.push({ path: path.join(context.paths.liveDir, '.claude', 'CLAUDE.md'), content: claudeContent });
1210
+ files.push({
1211
+ path: path.join(context.paths.liveDir, '.claude', 'agent-run-settings.json'),
1212
+ content: renderClaudeSettings(env, configRoot, context, trace)
1213
+ });
1214
+ files.push(...renderNativeSkillFiles(context, 'claude'));
1215
+ }
1144
1216
  files.push(...renderGuardShims(context));
1145
1217
  return {
1146
1218
  agentDir,
@@ -1161,15 +1233,22 @@ function syncAgentProfile(projectRoot, agentDir) {
1161
1233
  return rendered;
1162
1234
  }
1163
1235
  function removeLegacyGeneratedClaudeSettings(context) {
1164
- const legacyPath = path.join(context.agentDir, '.claude', 'settings.json');
1165
- if (!fs.existsSync(legacyPath)) {
1166
- return;
1167
- }
1168
- const actual = fs.readFileSync(legacyPath, 'utf8').replace(/\r\n/g, '\n');
1169
- const legacyGeneratedContent = legacyDefaultClaudeSettingsContent(context);
1170
- if (actual === legacyGeneratedContent) {
1171
- fs.rmSync(legacyPath);
1172
- verbose(`removed legacy generated Claude settings ${legacyPath}`);
1236
+ for (const legacyPath of [
1237
+ path.join(context.paths.liveDir, '.claude', 'settings.json'),
1238
+ path.join(context.profileDir, '.claude', 'settings.json')
1239
+ ]) {
1240
+ if (!fs.existsSync(legacyPath)) {
1241
+ continue;
1242
+ }
1243
+ const actual = fs.readFileSync(legacyPath, 'utf8').replace(/\r\n/g, '\n');
1244
+ const legacyGeneratedContents = [
1245
+ legacyDefaultClaudeSettingsContent(context, context.agentDir),
1246
+ legacyDefaultClaudeSettingsContent(context, context.profileDir)
1247
+ ];
1248
+ if (legacyGeneratedContents.includes(actual)) {
1249
+ fs.rmSync(legacyPath);
1250
+ verbose(`removed legacy generated Claude settings ${legacyPath}`);
1251
+ }
1173
1252
  }
1174
1253
  }
1175
1254
  function checkRenderedProfile(projectRoot, agentDir) {
@@ -1191,6 +1270,7 @@ function checkRenderedProfile(projectRoot, agentDir) {
1191
1270
  rendered.context.paths.reviewDir,
1192
1271
  rendered.context.paths.memoriesDir,
1193
1272
  rendered.context.paths.codexHomeDir,
1273
+ rendered.context.paths.liveDir,
1194
1274
  rendered.context.paths.overridesDir,
1195
1275
  rendered.context.paths.codexSkillsDir,
1196
1276
  rendered.context.paths.claudeSkillsDir,
@@ -1224,7 +1304,7 @@ function checkRenderedProfile(projectRoot, agentDir) {
1224
1304
  }
1225
1305
  return findings;
1226
1306
  }
1227
- function renderSkills(env, configRoot, manifest, context) {
1307
+ function renderSkills(env, configRoot, manifest, context, trace) {
1228
1308
  const skills = [];
1229
1309
  for (const name of manifest.skills.install) {
1230
1310
  const sourceTemplate = manifest.skills.overrides[name] ?? `global/skills/${name}/SKILL.md.njk`;
@@ -1232,7 +1312,7 @@ function renderSkills(env, configRoot, manifest, context) {
1232
1312
  if (!fs.existsSync(sourcePath)) {
1233
1313
  throw new Error(`missing skill template for ${name}: ${sourcePath}`);
1234
1314
  }
1235
- const renderedContent = renderTemplateFile(env, configRoot, sourceTemplate, context);
1315
+ const renderedContent = renderTemplateFile(env, configRoot, sourceTemplate, context, trace);
1236
1316
  assertNoUnexpandedTemplateVars(`skill ${name}`, renderedContent);
1237
1317
  validateRenderedSkill(renderedContent, sourcePath);
1238
1318
  const description = extractSkillDescription(renderedContent);
@@ -1240,41 +1320,45 @@ function renderSkills(env, configRoot, manifest, context) {
1240
1320
  }
1241
1321
  return skills;
1242
1322
  }
1243
- function renderNativeSkillFiles(context) {
1323
+ function renderNativeSkillFiles(context, targetTool = null) {
1244
1324
  const files = [];
1245
1325
  for (const skill of context.skills) {
1246
- files.push({
1247
- path: path.join(context.paths.codexSkillsDir, skill.name, 'SKILL.md'),
1248
- content: skill.renderedContent
1249
- });
1250
- files.push({
1251
- path: path.join(context.paths.claudeSkillsDir, skill.name, 'SKILL.md'),
1252
- content: skill.renderedContent
1253
- });
1326
+ if (targetTool === null || targetTool === 'codex') {
1327
+ files.push({
1328
+ path: path.join(context.paths.codexSkillsDir, skill.name, 'SKILL.md'),
1329
+ content: skill.renderedContent
1330
+ });
1331
+ }
1332
+ if (targetTool === null || targetTool === 'claude') {
1333
+ files.push({
1334
+ path: path.join(context.paths.claudeSkillsDir, skill.name, 'SKILL.md'),
1335
+ content: skill.renderedContent
1336
+ });
1337
+ }
1254
1338
  }
1255
1339
  return files;
1256
1340
  }
1257
- function renderToolInstructions(templateName, env, configRoot, context, isClaude) {
1341
+ function renderToolInstructions(templateName, env, configRoot, context, isClaude, trace) {
1258
1342
  const templatePath = `global/tool-templates/${templateName}.njk`;
1259
1343
  const absoluteTemplate = path.join(configRoot, templatePath);
1260
1344
  const content = fs.existsSync(absoluteTemplate)
1261
- ? renderTemplateFile(env, configRoot, templatePath, context)
1345
+ ? renderTemplateFile(env, configRoot, templatePath, context, trace)
1262
1346
  : renderInlineTemplate(env, defaultToolInstructionsTemplate(isClaude), context);
1263
1347
  assertNoUnexpandedTemplateVars(templateName, content);
1264
1348
  return content.replace(/\n*$/, '\n');
1265
1349
  }
1266
- function renderCodexConfig(env, configRoot, context) {
1350
+ function renderCodexConfig(env, configRoot, context, trace) {
1267
1351
  const templatePath = resolveProfileOverrideTemplate(configRoot, context, 'codex-config.toml.njk', 'global/tool-templates/codex-config.toml.njk');
1268
1352
  const content = templatePath !== null
1269
- ? renderTemplateFile(env, configRoot, templatePath, context)
1353
+ ? renderTemplateFile(env, configRoot, templatePath, context, trace)
1270
1354
  : defaultCodexConfigContent(context);
1271
1355
  assertNoUnexpandedTemplateVars('config.toml', content);
1272
1356
  return content.replace(/\n*$/, '\n');
1273
1357
  }
1274
- function renderClaudeSettings(env, configRoot, context) {
1358
+ function renderClaudeSettings(env, configRoot, context, trace) {
1275
1359
  const templatePath = resolveProfileOverrideTemplate(configRoot, context, 'claude-settings.json.njk', 'global/tool-templates/claude-settings.json.njk');
1276
1360
  const content = templatePath !== null
1277
- ? renderTemplateFile(env, configRoot, templatePath, context)
1361
+ ? renderTemplateFile(env, configRoot, templatePath, context, trace)
1278
1362
  : defaultClaudeSettingsContent(context);
1279
1363
  assertNoUnexpandedTemplateVars('claude settings.json', content);
1280
1364
  return content.replace(/\n*$/, '\n');
@@ -1312,7 +1396,7 @@ function syncRuntimeDirs(context) {
1312
1396
  context.paths.codexSkillsDir,
1313
1397
  context.paths.claudeSkillsDir,
1314
1398
  context.paths.binDir,
1315
- path.join(context.agentDir, '.claude')
1399
+ path.join(context.paths.liveDir, '.claude')
1316
1400
  ]) {
1317
1401
  fs.mkdirSync(dir, { recursive: true });
1318
1402
  }
@@ -1346,8 +1430,9 @@ function extractSkillDescription(content) {
1346
1430
  }
1347
1431
  return '';
1348
1432
  }
1349
- function renderLegacyAgentsMods(sourceFile, stack = []) {
1433
+ function renderLegacyAgentsMods(sourceFile, stack = [], trace) {
1350
1434
  const resolvedSource = path.resolve(sourceFile);
1435
+ trace?.sourceFiles.add(resolvedSource);
1351
1436
  if (stack.includes(resolvedSource)) {
1352
1437
  throw new Error(`Include cycle detected: ${[...stack, resolvedSource].join(' -> ')}`);
1353
1438
  }
@@ -1367,7 +1452,9 @@ function renderLegacyAgentsMods(sourceFile, stack = []) {
1367
1452
  if (!includePath) {
1368
1453
  continue;
1369
1454
  }
1370
- output.push(renderLegacyAgentsMods(resolveIncludePath(resolvedSource, includePath), nextStack));
1455
+ const resolvedInclude = resolveIncludePath(resolvedSource, includePath);
1456
+ trace?.sourceFiles.add(resolvedInclude);
1457
+ output.push(renderLegacyAgentsMods(resolvedInclude, nextStack, trace));
1371
1458
  if (!contentStarted) {
1372
1459
  sawLeadingInclude = true;
1373
1460
  }
@@ -1522,17 +1609,19 @@ function formatError(error) {
1522
1609
  return error instanceof Error ? error.message : String(error);
1523
1610
  }
1524
1611
  function runCodex(realBinary, permissionArgs, agentDir, configRoot, args, projectRoot, wrapperArgs) {
1525
- const agentsPath = path.join(agentDir, 'AGENTS.md');
1612
+ const liveDir = profileLiveDir(agentDir);
1613
+ const agentsPath = path.join(liveDir, 'AGENTS.md');
1526
1614
  if (!fs.existsSync(agentsPath)) {
1527
1615
  failMissingConfig('codex', agentDir);
1528
1616
  }
1529
- const guardBin = path.join(agentDir, 'bin');
1530
- const codexHomeDir = path.join(agentDir, 'memories', 'codex-home');
1617
+ const guardBin = path.join(liveDir, 'bin');
1618
+ const codexHomeDir = path.join(liveDir, 'memories', 'codex-home');
1531
1619
  fs.mkdirSync(codexHomeDir, { recursive: true });
1532
1620
  const env = {
1533
1621
  ...process.env,
1534
1622
  CODEX_HOME: codexHomeDir,
1535
- AGENT_DIR: agentDir,
1623
+ AGENT_DIR: liveDir,
1624
+ AGENT_PROFILE_DIR: agentDir,
1536
1625
  AGENT_RUN_PROJECT_ROOT: projectRoot,
1537
1626
  PATH: `${guardBin}${path.delimiter}${process.env.PATH ?? ''}`
1538
1627
  };
@@ -1561,16 +1650,18 @@ function buildCodexRuntimeArgs(wrapperArgs) {
1561
1650
  return ['-a', 'never', '-s', 'danger-full-access'];
1562
1651
  }
1563
1652
  function runClaude(realBinary, permissionArgs, agentDir, configRoot, args, projectRoot, wrapperArgs) {
1564
- const claudePath = path.join(agentDir, 'CLAUDE.md');
1653
+ const liveDir = profileLiveDir(agentDir);
1654
+ const claudePath = path.join(liveDir, 'CLAUDE.md');
1565
1655
  if (!fs.existsSync(claudePath)) {
1566
1656
  failMissingConfig('claude', agentDir);
1567
1657
  }
1568
- const guardBin = path.join(agentDir, 'bin');
1569
- const claudeConfigDir = path.join(agentDir, '.claude');
1658
+ const guardBin = path.join(liveDir, 'bin');
1659
+ const claudeConfigDir = path.join(liveDir, '.claude');
1570
1660
  const env = {
1571
1661
  ...process.env,
1572
1662
  CLAUDE_CONFIG_DIR: claudeConfigDir,
1573
- AGENT_DIR: agentDir,
1663
+ AGENT_DIR: liveDir,
1664
+ AGENT_PROFILE_DIR: agentDir,
1574
1665
  AGENT_RUN_PROJECT_ROOT: projectRoot,
1575
1666
  PATH: `${guardBin}${path.delimiter}${process.env.PATH ?? ''}`
1576
1667
  };
@@ -1581,11 +1672,14 @@ function runClaude(realBinary, permissionArgs, agentDir, configRoot, args, proje
1581
1672
  '--add-dir',
1582
1673
  projectRoot,
1583
1674
  '--add-dir',
1584
- agentDir,
1675
+ liveDir,
1585
1676
  ...globalMemoryArgs(configRoot),
1586
1677
  ...args
1587
1678
  ], shouldUseShell(realBinary), env, projectRoot, (code) => postflightProjectCheck(projectRoot, agentDir, wrapperArgs.local, code));
1588
1679
  }
1680
+ function profileLiveDir(agentDir) {
1681
+ return path.join(agentDir, LIVE_DIR_NAME);
1682
+ }
1589
1683
  function globalMemoryArgs(configRoot) {
1590
1684
  const memoryDir = globalMemoryDir(configRoot);
1591
1685
  return fs.existsSync(memoryDir) ? ['--add-dir', memoryDir] : [];
@@ -2135,6 +2229,12 @@ function defaultLocalTemplate(_profile) {
2135
2229
  '{{ agentDir }}',
2136
2230
  '```',
2137
2231
  '',
2232
+ 'Profile source directory:',
2233
+ '',
2234
+ '```text',
2235
+ '{{ profileDir }}',
2236
+ '```',
2237
+ '',
2138
2238
  'Add project-specific rules here.',
2139
2239
  ''
2140
2240
  ].join('\n');
@@ -2177,7 +2277,8 @@ function defaultNoAiFilesSnippet() {
2177
2277
  '## Agent File Storage',
2178
2278
  '',
2179
2279
  'Do not create AGENTS.md, CLAUDE.md, .agents, .claude, .codex, or other agent runtime files inside the project repository.',
2180
- 'Agent-only files belong under {{ agentDir }}.',
2280
+ 'Generated agent-only files belong under {{ paths.liveDir }}.',
2281
+ 'Source config files belong under {{ profileDir }}.',
2181
2282
  ''
2182
2283
  ].join('\n');
2183
2284
  }
@@ -2249,8 +2350,8 @@ function defaultToolInstructionsTemplate(isClaude) {
2249
2350
  'Do not edit this file directly. Edit:',
2250
2351
  '',
2251
2352
  '```text',
2252
- '{{ agentDir }}/agent-run.jsonc',
2253
- '{{ agentDir }}/local.md.njk',
2353
+ '{{ profileDir }}/agent-run.jsonc',
2354
+ '{{ profileDir }}/local.md.njk',
2254
2355
  '```',
2255
2356
  '',
2256
2357
  '{% for section in renderedAgentSections %}',
@@ -2271,6 +2372,12 @@ function defaultToolInstructionsTemplate(isClaude) {
2271
2372
  '{{ agentDir }}',
2272
2373
  '```',
2273
2374
  '',
2375
+ 'Profile source directory:',
2376
+ '',
2377
+ '```text',
2378
+ '{{ profileDir }}',
2379
+ '```',
2380
+ '',
2274
2381
  'Review directory:',
2275
2382
  '',
2276
2383
  '```text',
@@ -2310,13 +2417,14 @@ function defaultToolInstructionsTemplate(isClaude) {
2310
2417
  '## Tool Note',
2311
2418
  '',
2312
2419
  isClaude
2313
- ? 'Claude uses the generated config directory under {{ agentDir }}/.claude and may read {{ agentDir }} via `--add-dir`.'
2420
+ ? 'Claude uses the generated config directory under {{ paths.liveDir }}/.claude and may read {{ paths.liveDir }} via `--add-dir`.'
2314
2421
  : 'Codex uses {{ agentDir }}/AGENTS.md as `system_prompt_file` and {{ paths.codexHomeDir }} as CODEX_HOME.',
2315
2422
  '',
2316
2423
  '## Mandatory Path Rule',
2317
2424
  '',
2318
2425
  'Do not create AGENTS.md, CLAUDE.md, .agents, .claude, .codex, or AI-related files inside the project repository.',
2319
- 'Agent-only files must be stored under the agent directory shown above.',
2426
+ 'Generated agent-only files must be stored under the agent directory shown above.',
2427
+ 'Source config files must be stored under the profile source directory shown above.',
2320
2428
  ''
2321
2429
  ].join('\n');
2322
2430
  }
@@ -2331,6 +2439,7 @@ function defaultCodexConfigTemplate() {
2331
2439
  'writable_roots = [',
2332
2440
  ' "{{ projectRoot }}",',
2333
2441
  ' "{{ agentDir }}",',
2442
+ ' "{{ profileDir }}",',
2334
2443
  ' "{{ paths.globalMemoryDir }}"',
2335
2444
  ']',
2336
2445
  'network_access = false',
@@ -2341,6 +2450,7 @@ function defaultClaudeSettingsTemplate() {
2341
2450
  const envBlock = [
2342
2451
  ' "env": {',
2343
2452
  ' "AGENT_DIR": "{{ agentDir }}",',
2453
+ ' "AGENT_PROFILE_DIR": "{{ profileDir }}",',
2344
2454
  ' "AGENT_RUN_PROJECT_ROOT": "{{ projectRoot }}",',
2345
2455
  ' "AGENT_GLOBAL_MEMORY_DIR": "{{ paths.globalMemoryDir }}"',
2346
2456
  ' }'
@@ -2371,6 +2481,7 @@ function defaultCodexConfigContent(context) {
2371
2481
  'writable_roots = [',
2372
2482
  ` ${jsonString(context.projectRoot)},`,
2373
2483
  ` ${jsonString(context.agentDir)},`,
2484
+ ` ${jsonString(context.profileDir)},`,
2374
2485
  ` ${jsonString(context.paths.globalMemoryDir)}`,
2375
2486
  ']',
2376
2487
  'network_access = false',
@@ -2381,6 +2492,7 @@ function defaultClaudeSettingsContent(context) {
2381
2492
  const settings = {
2382
2493
  env: {
2383
2494
  AGENT_DIR: context.agentDir,
2495
+ AGENT_PROFILE_DIR: context.profileDir,
2384
2496
  AGENT_RUN_PROJECT_ROOT: context.projectRoot,
2385
2497
  AGENT_GLOBAL_MEMORY_DIR: context.paths.globalMemoryDir
2386
2498
  }
@@ -2390,10 +2502,10 @@ function defaultClaudeSettingsContent(context) {
2390
2502
  }
2391
2503
  return `${JSON.stringify(settings, null, 2)}\n`;
2392
2504
  }
2393
- function legacyDefaultClaudeSettingsContent(context) {
2505
+ function legacyDefaultClaudeSettingsContent(context, agentDir) {
2394
2506
  return `${JSON.stringify({
2395
2507
  env: {
2396
- AGENT_DIR: context.agentDir,
2508
+ AGENT_DIR: agentDir,
2397
2509
  AGENT_RUN_PROJECT_ROOT: context.projectRoot,
2398
2510
  AGENT_GLOBAL_MEMORY_DIR: context.paths.globalMemoryDir
2399
2511
  }
@@ -1,21 +1,5 @@
1
- # Generated agent-run files
2
- **/AGENTS.md
3
- **/CLAUDE.md
4
- **/GEMINI.md
5
- **/config.toml
6
-
7
- # Generated native agent homes
8
- **/.agents/
9
- **/.claude/
10
- **/.codex/
11
-
12
- # Generated runtime files
13
- **/bin/
14
- **/reviews/
15
- **/memories/
16
-
17
- # Generated review reports
18
- **/REVIEW-*.md
1
+ # Generated agent-run live profiles
2
+ **/live/
19
3
 
20
4
  # Optional generated caches
21
5
  **/.agent-run-cache/
@@ -7,3 +7,9 @@ Agent directory:
7
7
  ```text
8
8
  {{ agentDir }}
9
9
  ```
10
+
11
+ Profile source directory:
12
+
13
+ ```text
14
+ {{ profileDir }}
15
+ ```
@@ -10,6 +10,7 @@ Do not edit this generated file. Edit `agent-run.jsonc` and `local.md.njk`.
10
10
 
11
11
  - projectRoot: `{{ projectRoot }}`
12
12
  - agentDir: `{{ agentDir }}`
13
+ - profileDir: `{{ profileDir }}`
13
14
  - reviewFile: `{{ paths.reviewFile }}`
14
15
  - memoriesDir: `{{ paths.memoriesDir }}`
15
16
  - globalMemoryDir: `{{ paths.globalMemoryDir }}`
@@ -1,6 +1,7 @@
1
1
  {% if permissionsAllow.length %}{
2
2
  "env": {
3
3
  "AGENT_DIR": "{{ agentDir }}",
4
+ "AGENT_PROFILE_DIR": "{{ profileDir }}",
4
5
  "AGENT_RUN_PROJECT_ROOT": "{{ projectRoot }}",
5
6
  "AGENT_GLOBAL_MEMORY_DIR": "{{ paths.globalMemoryDir }}",
6
7
  "STARTER_PROFILE": "{{ profile }}"
@@ -14,6 +15,7 @@
14
15
  {% else %}{
15
16
  "env": {
16
17
  "AGENT_DIR": "{{ agentDir }}",
18
+ "AGENT_PROFILE_DIR": "{{ profileDir }}",
17
19
  "AGENT_RUN_PROJECT_ROOT": "{{ projectRoot }}",
18
20
  "AGENT_GLOBAL_MEMORY_DIR": "{{ paths.globalMemoryDir }}",
19
21
  "STARTER_PROFILE": "{{ profile }}"
@@ -6,6 +6,7 @@ sandbox_mode = "workspace-write"
6
6
  writable_roots = [
7
7
  "{{ projectRoot }}",
8
8
  "{{ agentDir }}",
9
+ "{{ profileDir }}",
9
10
  "{{ paths.memoriesDir }}",
10
11
  "{{ paths.globalMemoryDir }}"
11
12
  ]
@@ -3,3 +3,4 @@
3
3
  This starter profile belongs to `{{ profile }}`.
4
4
 
5
5
  Use the project root at `{{ projectRoot }}` and keep generated files in `{{ agentDir }}`.
6
+ Keep source profile edits in `{{ profileDir }}`.
@@ -1,6 +1,7 @@
1
1
  {% if permissionsAllow.length %}{
2
2
  "env": {
3
3
  "AGENT_DIR": "{{ agentDir }}",
4
+ "AGENT_PROFILE_DIR": "{{ profileDir }}",
4
5
  "AGENT_RUN_PROJECT_ROOT": "{{ projectRoot }}",
5
6
  "AGENT_GLOBAL_MEMORY_DIR": "{{ paths.globalMemoryDir }}",
6
7
  "STARTER_PROFILE": "{{ profile }}",
@@ -15,6 +16,7 @@
15
16
  {% else %}{
16
17
  "env": {
17
18
  "AGENT_DIR": "{{ agentDir }}",
19
+ "AGENT_PROFILE_DIR": "{{ profileDir }}",
18
20
  "AGENT_RUN_PROJECT_ROOT": "{{ projectRoot }}",
19
21
  "AGENT_GLOBAL_MEMORY_DIR": "{{ paths.globalMemoryDir }}",
20
22
  "STARTER_PROFILE": "{{ profile }}",
@@ -6,6 +6,7 @@ sandbox_mode = "workspace-write"
6
6
  writable_roots = [
7
7
  "{{ projectRoot }}",
8
8
  "{{ agentDir }}",
9
+ "{{ profileDir }}",
9
10
  "{{ paths.memoriesDir }}",
10
11
  "{{ paths.globalMemoryDir }}"
11
12
  ]
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@technomoron/agent-run",
3
- "version": "0.99.12",
3
+ "version": "0.99.14",
4
4
  "packageManager": "pnpm@10.28.1",
5
5
  "bin": {
6
6
  "agent-run": "dist/agent-run.js"