clavix 5.8.2 → 5.9.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.
Files changed (33) hide show
  1. package/dist/cli/commands/init.js +93 -3
  2. package/dist/cli/commands/update.js +5 -1
  3. package/dist/cli/helpers/init/config.d.ts +1 -1
  4. package/dist/cli/helpers/init/config.js +7 -1
  5. package/dist/core/adapters/claude-code-adapter.d.ts +3 -0
  6. package/dist/core/adapters/claude-code-adapter.js +5 -0
  7. package/dist/core/adapters/gemini-adapter.d.ts +3 -1
  8. package/dist/core/adapters/gemini-adapter.js +25 -6
  9. package/dist/core/adapters/llxprt-adapter.d.ts +3 -1
  10. package/dist/core/adapters/llxprt-adapter.js +25 -6
  11. package/dist/core/adapters/qwen-adapter.d.ts +3 -1
  12. package/dist/core/adapters/qwen-adapter.js +25 -6
  13. package/dist/core/adapters/toml-formatting-adapter.d.ts +3 -0
  14. package/dist/core/adapters/toml-formatting-adapter.js +2 -0
  15. package/dist/core/adapters/universal-adapter.d.ts +3 -1
  16. package/dist/core/adapters/universal-adapter.js +6 -7
  17. package/dist/core/agent-manager.d.ts +3 -1
  18. package/dist/core/agent-manager.js +8 -6
  19. package/dist/templates/slash-commands/_canonical/archive.md +1 -1
  20. package/dist/templates/slash-commands/_canonical/implement.md +1 -1
  21. package/dist/templates/slash-commands/_canonical/improve.md +1 -1
  22. package/dist/templates/slash-commands/_canonical/plan.md +17 -9
  23. package/dist/templates/slash-commands/_canonical/prd.md +10 -2
  24. package/dist/templates/slash-commands/_canonical/refine.md +1 -1
  25. package/dist/templates/slash-commands/_canonical/start.md +3 -1
  26. package/dist/templates/slash-commands/_canonical/summarize.md +7 -1
  27. package/dist/templates/slash-commands/_canonical/verify.md +1 -1
  28. package/dist/types/config.d.ts +10 -1
  29. package/dist/utils/path-resolver.d.ts +28 -0
  30. package/dist/utils/path-resolver.js +57 -0
  31. package/dist/utils/schemas.d.ts +24 -9
  32. package/dist/utils/schemas.js +16 -1
  33. package/package.json +2 -1
@@ -25,8 +25,8 @@ export default class Init extends Command {
25
25
  async run() {
26
26
  this.log(chalk.bold.cyan('\nšŸš€ Clavix Initialization\n'));
27
27
  try {
28
- const agentManager = new AgentManager();
29
28
  let existingIntegrations = [];
29
+ let existingConfig;
30
30
  // Load existing config if present
31
31
  if (await FileSystem.exists('.clavix/config.json')) {
32
32
  try {
@@ -37,6 +37,7 @@ export default class Init extends Command {
37
37
  if (validationResult.success && validationResult.data) {
38
38
  existingIntegrations =
39
39
  validationResult.data.integrations || validationResult.data.providers || [];
40
+ existingConfig = validationResult.data;
40
41
  // Log warnings (non-blocking)
41
42
  if (validationResult.warnings) {
42
43
  for (const warning of validationResult.warnings) {
@@ -60,6 +61,8 @@ export default class Init extends Command {
60
61
  // Continue with empty array - will prompt for new configuration
61
62
  }
62
63
  }
64
+ // Initialize agent manager with existing config (for custom integration paths)
65
+ const agentManager = new AgentManager(existingConfig);
63
66
  // Check if already initialized
64
67
  if (await FileSystem.exists('.clavix')) {
65
68
  // Show current state
@@ -176,12 +179,93 @@ export default class Init extends Command {
176
179
  }
177
180
  // If 'skip': do nothing
178
181
  }
182
+ // Collect custom integration paths (e.g., for Codex with $CODEX_HOME)
183
+ const integrationPaths = {};
184
+ // Prompt about Codex path if Codex is selected
185
+ if (selectedIntegrations.includes('codex')) {
186
+ this.log(chalk.cyan('\nšŸ”§ Codex Configuration'));
187
+ const hasEnvVar = process.env.CODEX_HOME;
188
+ const defaultPath = '~/.codex/prompts';
189
+ if (hasEnvVar) {
190
+ // $CODEX_HOME is detected - ask for confirmation
191
+ const { useEnvPath } = await inquirer.prompt([
192
+ {
193
+ type: 'confirm',
194
+ name: 'useEnvPath',
195
+ message: `Detected $CODEX_HOME=${hasEnvVar}. Use this path instead of ${defaultPath}?`,
196
+ default: true,
197
+ },
198
+ ]);
199
+ if (useEnvPath) {
200
+ integrationPaths.codex = hasEnvVar;
201
+ this.log(chalk.gray(` āœ“ Using $CODEX_HOME: ${hasEnvVar}`));
202
+ }
203
+ else {
204
+ // Ask if they want to use a custom path
205
+ const { useCustomPath } = await inquirer.prompt([
206
+ {
207
+ type: 'confirm',
208
+ name: 'useCustomPath',
209
+ message: 'Use a custom Codex prompts directory?',
210
+ default: false,
211
+ },
212
+ ]);
213
+ if (useCustomPath) {
214
+ const { customPath } = await inquirer.prompt([
215
+ {
216
+ type: 'input',
217
+ name: 'customPath',
218
+ message: 'Enter path to Codex prompts directory:',
219
+ default: defaultPath,
220
+ validate: (input) => {
221
+ if (!input || input.trim().length === 0) {
222
+ return 'Path cannot be empty';
223
+ }
224
+ return true;
225
+ },
226
+ },
227
+ ]);
228
+ integrationPaths.codex = customPath;
229
+ this.log(chalk.gray(` āœ“ Using custom path: ${customPath}`));
230
+ }
231
+ }
232
+ }
233
+ else {
234
+ // No $CODEX_HOME - ask if they want a custom path
235
+ const { useCustomPath } = await inquirer.prompt([
236
+ {
237
+ type: 'confirm',
238
+ name: 'useCustomPath',
239
+ message: 'Use a custom Codex prompts directory?',
240
+ default: false,
241
+ },
242
+ ]);
243
+ if (useCustomPath) {
244
+ const { customPath } = await inquirer.prompt([
245
+ {
246
+ type: 'input',
247
+ name: 'customPath',
248
+ message: 'Enter path to Codex prompts directory:',
249
+ default: defaultPath,
250
+ validate: (input) => {
251
+ if (!input || input.trim().length === 0) {
252
+ return 'Path cannot be empty';
253
+ }
254
+ return true;
255
+ },
256
+ },
257
+ ]);
258
+ integrationPaths.codex = customPath;
259
+ this.log(chalk.gray(` āœ“ Using custom path: ${customPath}`));
260
+ }
261
+ }
262
+ }
179
263
  // Create .clavix directory structure
180
264
  this.log(chalk.cyan('\nšŸ“ Creating directory structure...'));
181
265
  await this.createDirectoryStructure();
182
266
  // Generate config
183
267
  this.log(chalk.cyan('āš™ļø Generating configuration...'));
184
- await this.generateConfig(selectedIntegrations);
268
+ await this.generateConfig(selectedIntegrations, integrationPaths);
185
269
  // Generate INSTRUCTIONS.md and QUICKSTART.md
186
270
  await this.generateInstructions();
187
271
  await this.generateQuickstart();
@@ -396,11 +480,17 @@ export default class Init extends Command {
396
480
  await FileSystem.ensureDir(dir);
397
481
  }
398
482
  }
399
- async generateConfig(integrations) {
483
+ async generateConfig(integrations, integrationPaths = {}) {
400
484
  const config = {
401
485
  ...DEFAULT_CONFIG,
402
486
  integrations,
403
487
  };
488
+ // Add integration paths to experimental if any
489
+ if (Object.keys(integrationPaths).length > 0) {
490
+ config.experimental = {
491
+ integrationPaths,
492
+ };
493
+ }
404
494
  const configPath = '.clavix/config.json';
405
495
  const configContent = JSON.stringify(config, null, 2);
406
496
  await FileSystem.writeFileAtomic(configPath, configContent);
@@ -72,6 +72,8 @@ export default class Update extends Command {
72
72
  this.log(chalk.yellow(` ⚠ ${warning}`));
73
73
  }
74
74
  }
75
+ // Type assertion: validationResult.data is User type which has optional version
76
+ // We know version exists in valid configs, so we can assert
75
77
  config = validationResult.data;
76
78
  }
77
79
  catch (error) {
@@ -84,8 +86,10 @@ export default class Update extends Command {
84
86
  chalk.cyan('clavix init') +
85
87
  chalk.yellow(' to regenerate.'));
86
88
  }
89
+ // Handle legacy 'providers' field for backward compatibility
87
90
  const integrations = config.integrations || config.providers || ['claude-code'];
88
- const agentManager = new AgentManager();
91
+ // Initialize agent manager with config (for custom integration paths)
92
+ const agentManager = new AgentManager(config);
89
93
  const updateDocs = flags['docs-only'] || (!flags['docs-only'] && !flags['commands-only']);
90
94
  const updateCommands = flags['commands-only'] || (!flags['docs-only'] && !flags['commands-only']);
91
95
  let updatedCount = 0;
@@ -12,7 +12,7 @@ export declare function loadExistingConfig(): Promise<{
12
12
  /**
13
13
  * Generate and save the Clavix config file
14
14
  */
15
- export declare function generateConfig(integrations: string[]): Promise<void>;
15
+ export declare function generateConfig(integrations: string[], integrationPaths?: Record<string, string>): Promise<void>;
16
16
  /**
17
17
  * Check if Clavix is already initialized in the current directory
18
18
  */
@@ -31,11 +31,17 @@ export async function loadExistingConfig() {
31
31
  /**
32
32
  * Generate and save the Clavix config file
33
33
  */
34
- export async function generateConfig(integrations) {
34
+ export async function generateConfig(integrations, integrationPaths = {}) {
35
35
  const config = {
36
36
  ...DEFAULT_CONFIG,
37
37
  integrations,
38
38
  };
39
+ // Add integration paths to experimental if any
40
+ if (Object.keys(integrationPaths).length > 0) {
41
+ config.experimental = {
42
+ integrationPaths,
43
+ };
44
+ }
39
45
  const configPath = '.clavix/config.json';
40
46
  const configContent = JSON.stringify(config, null, 2);
41
47
  await FileSystem.writeFileAtomic(configPath, configContent);
@@ -1,5 +1,6 @@
1
1
  import { BaseAdapter } from './base-adapter.js';
2
2
  import { ManagedBlock } from '../../types/agent.js';
3
+ import { ClavixConfig } from '../../types/config.js';
3
4
  /**
4
5
  * Claude Code agent adapter
5
6
  */
@@ -11,6 +12,8 @@ export declare class ClaudeCodeAdapter extends BaseAdapter {
11
12
  readonly features: {
12
13
  supportsSubdirectories: boolean;
13
14
  };
15
+ protected readonly userConfig?: ClavixConfig;
16
+ constructor(userConfig?: ClavixConfig);
14
17
  /**
15
18
  * Detect if Claude Code is available in the project
16
19
  */
@@ -14,6 +14,11 @@ export class ClaudeCodeAdapter extends BaseAdapter {
14
14
  features = {
15
15
  supportsSubdirectories: true,
16
16
  };
17
+ userConfig;
18
+ constructor(userConfig) {
19
+ super();
20
+ this.userConfig = userConfig;
21
+ }
17
22
  /**
18
23
  * Detect if Claude Code is available in the project
19
24
  */
@@ -1,11 +1,13 @@
1
1
  import { TomlFormattingAdapter } from './toml-formatting-adapter.js';
2
+ import { ClavixConfig } from '../../types/config.js';
2
3
  /**
3
4
  * Gemini CLI adapter
4
5
  * Commands stored as TOML files under .gemini/commands/clavix by default
5
6
  */
6
7
  export declare class GeminiAdapter extends TomlFormattingAdapter {
7
- constructor(options?: {
8
+ constructor(userConfigOrOptions?: ClavixConfig | {
8
9
  useNamespace?: boolean;
10
+ userConfig?: ClavixConfig;
9
11
  });
10
12
  }
11
13
  //# sourceMappingURL=gemini-adapter.d.ts.map
@@ -4,12 +4,31 @@ import { TomlFormattingAdapter } from './toml-formatting-adapter.js';
4
4
  * Commands stored as TOML files under .gemini/commands/clavix by default
5
5
  */
6
6
  export class GeminiAdapter extends TomlFormattingAdapter {
7
- constructor(options = {}) {
8
- super({
9
- name: 'gemini',
10
- displayName: 'Gemini CLI',
11
- rootDir: '.gemini',
12
- }, options);
7
+ constructor(userConfigOrOptions) {
8
+ // Support both old API (options object) and new API (userConfig directly)
9
+ if (!userConfigOrOptions) {
10
+ super({
11
+ name: 'gemini',
12
+ displayName: 'Gemini CLI',
13
+ rootDir: '.gemini',
14
+ });
15
+ }
16
+ else if ('useNamespace' in userConfigOrOptions) {
17
+ // It's the options object
18
+ super({
19
+ name: 'gemini',
20
+ displayName: 'Gemini CLI',
21
+ rootDir: '.gemini',
22
+ }, userConfigOrOptions);
23
+ }
24
+ else {
25
+ // It's the userConfig directly - pass as options
26
+ super({
27
+ name: 'gemini',
28
+ displayName: 'Gemini CLI',
29
+ rootDir: '.gemini',
30
+ }, { userConfig: userConfigOrOptions });
31
+ }
13
32
  }
14
33
  }
15
34
  //# sourceMappingURL=gemini-adapter.js.map
@@ -1,11 +1,13 @@
1
1
  import { TomlFormattingAdapter } from './toml-formatting-adapter.js';
2
+ import { ClavixConfig } from '../../types/config.js';
2
3
  /**
3
4
  * LLXPRT adapter
4
5
  * Commands stored as TOML files under .llxprt/commands/clavix by default
5
6
  */
6
7
  export declare class LlxprtAdapter extends TomlFormattingAdapter {
7
- constructor(options?: {
8
+ constructor(userConfigOrOptions?: ClavixConfig | {
8
9
  useNamespace?: boolean;
10
+ userConfig?: ClavixConfig;
9
11
  });
10
12
  }
11
13
  //# sourceMappingURL=llxprt-adapter.d.ts.map
@@ -4,12 +4,31 @@ import { TomlFormattingAdapter } from './toml-formatting-adapter.js';
4
4
  * Commands stored as TOML files under .llxprt/commands/clavix by default
5
5
  */
6
6
  export class LlxprtAdapter extends TomlFormattingAdapter {
7
- constructor(options = {}) {
8
- super({
9
- name: 'llxprt',
10
- displayName: 'LLXPRT',
11
- rootDir: '.llxprt',
12
- }, options);
7
+ constructor(userConfigOrOptions) {
8
+ // Support both old API (options object) and new API (userConfig directly)
9
+ if (!userConfigOrOptions) {
10
+ super({
11
+ name: 'llxprt',
12
+ displayName: 'LLXPRT',
13
+ rootDir: '.llxprt',
14
+ });
15
+ }
16
+ else if ('useNamespace' in userConfigOrOptions) {
17
+ // It's the options object
18
+ super({
19
+ name: 'llxprt',
20
+ displayName: 'LLXPRT',
21
+ rootDir: '.llxprt',
22
+ }, userConfigOrOptions);
23
+ }
24
+ else {
25
+ // It's the userConfig directly - pass as options
26
+ super({
27
+ name: 'llxprt',
28
+ displayName: 'LLXPRT',
29
+ rootDir: '.llxprt',
30
+ }, { userConfig: userConfigOrOptions });
31
+ }
13
32
  }
14
33
  }
15
34
  //# sourceMappingURL=llxprt-adapter.js.map
@@ -1,11 +1,13 @@
1
1
  import { TomlFormattingAdapter } from './toml-formatting-adapter.js';
2
+ import { ClavixConfig } from '../../types/config.js';
2
3
  /**
3
4
  * Qwen Code CLI adapter
4
5
  * Commands stored as TOML files under .qwen/commands/clavix by default
5
6
  */
6
7
  export declare class QwenAdapter extends TomlFormattingAdapter {
7
- constructor(options?: {
8
+ constructor(userConfigOrOptions?: ClavixConfig | {
8
9
  useNamespace?: boolean;
10
+ userConfig?: ClavixConfig;
9
11
  });
10
12
  }
11
13
  //# sourceMappingURL=qwen-adapter.d.ts.map
@@ -4,12 +4,31 @@ import { TomlFormattingAdapter } from './toml-formatting-adapter.js';
4
4
  * Commands stored as TOML files under .qwen/commands/clavix by default
5
5
  */
6
6
  export class QwenAdapter extends TomlFormattingAdapter {
7
- constructor(options = {}) {
8
- super({
9
- name: 'qwen',
10
- displayName: 'Qwen Code',
11
- rootDir: '.qwen',
12
- }, options);
7
+ constructor(userConfigOrOptions) {
8
+ // Support both old API (options object) and new API (userConfig directly)
9
+ if (!userConfigOrOptions) {
10
+ super({
11
+ name: 'qwen',
12
+ displayName: 'Qwen Code',
13
+ rootDir: '.qwen',
14
+ });
15
+ }
16
+ else if ('useNamespace' in userConfigOrOptions) {
17
+ // It's the options object
18
+ super({
19
+ name: 'qwen',
20
+ displayName: 'Qwen Code',
21
+ rootDir: '.qwen',
22
+ }, userConfigOrOptions);
23
+ }
24
+ else {
25
+ // It's the userConfig directly - pass as options
26
+ super({
27
+ name: 'qwen',
28
+ displayName: 'Qwen Code',
29
+ rootDir: '.qwen',
30
+ }, { userConfig: userConfigOrOptions });
31
+ }
13
32
  }
14
33
  }
15
34
  //# sourceMappingURL=qwen-adapter.js.map
@@ -1,5 +1,6 @@
1
1
  import { BaseAdapter } from './base-adapter.js';
2
2
  import { CommandTemplate } from '../../types/agent.js';
3
+ import { ClavixConfig } from '../../types/config.js';
3
4
  /**
4
5
  * Configuration for TOML-based adapters
5
6
  */
@@ -30,8 +31,10 @@ export declare abstract class TomlFormattingAdapter extends BaseAdapter {
30
31
  argumentPlaceholder: string;
31
32
  };
32
33
  protected readonly config: TomlAdapterConfig;
34
+ protected readonly userConfig?: ClavixConfig;
33
35
  constructor(config: TomlAdapterConfig, options?: {
34
36
  useNamespace?: boolean;
37
+ userConfig?: ClavixConfig;
35
38
  });
36
39
  get name(): string;
37
40
  get displayName(): string;
@@ -19,12 +19,14 @@ export class TomlFormattingAdapter extends BaseAdapter {
19
19
  argumentPlaceholder: '{{args}}',
20
20
  };
21
21
  config;
22
+ userConfig;
22
23
  constructor(config, options = {}) {
23
24
  super();
24
25
  this.config = {
25
26
  ...config,
26
27
  useNamespace: options.useNamespace ?? config.useNamespace ?? true,
27
28
  };
29
+ this.userConfig = options.userConfig;
28
30
  }
29
31
  get name() {
30
32
  return this.config.name;
@@ -13,10 +13,12 @@
13
13
  import { BaseAdapter } from './base-adapter.js';
14
14
  import { AdapterConfig } from '../../types/adapter-config.js';
15
15
  import { IntegrationFeatures } from '../../types/agent.js';
16
+ import { ClavixConfig } from '../../types/config.js';
16
17
  export declare class UniversalAdapter extends BaseAdapter {
17
18
  private config;
18
19
  readonly features: IntegrationFeatures;
19
- constructor(config: AdapterConfig);
20
+ private userConfig?;
21
+ constructor(config: AdapterConfig, userConfig?: ClavixConfig);
20
22
  get name(): string;
21
23
  get displayName(): string;
22
24
  get directory(): string;
@@ -11,14 +11,16 @@
11
11
  * @since v5.3.0
12
12
  */
13
13
  import { BaseAdapter } from './base-adapter.js';
14
+ import { resolveIntegrationPath } from '../../utils/path-resolver.js';
14
15
  import * as path from 'path';
15
- import * as os from 'os';
16
16
  export class UniversalAdapter extends BaseAdapter {
17
17
  config;
18
18
  features;
19
- constructor(config) {
19
+ userConfig;
20
+ constructor(config, userConfig) {
20
21
  super();
21
22
  this.config = config;
23
+ this.userConfig = userConfig;
22
24
  // Set features from config for interface compatibility
23
25
  this.features = {
24
26
  supportsSubdirectories: config.features.supportsSubdirectories,
@@ -34,11 +36,8 @@ export class UniversalAdapter extends BaseAdapter {
34
36
  return this.config.displayName;
35
37
  }
36
38
  get directory() {
37
- // Expand ~ to home directory for global adapters
38
- if (this.config.directory.startsWith('~/')) {
39
- return this.config.directory.replace('~', os.homedir());
40
- }
41
- return this.config.directory;
39
+ // Use path resolver for proper environment variable and config override support
40
+ return resolveIntegrationPath(this.config, this.userConfig);
42
41
  }
43
42
  /**
44
43
  * Check if this adapter uses global (home directory) installation
@@ -1,4 +1,5 @@
1
1
  import { AgentAdapter, ValidationResult } from '../types/agent.js';
2
+ import { ClavixConfig } from '../types/config.js';
2
3
  /**
3
4
  * Agent Manager - handles agent detection and registration
4
5
  *
@@ -9,7 +10,8 @@ import { AgentAdapter, ValidationResult } from '../types/agent.js';
9
10
  */
10
11
  export declare class AgentManager {
11
12
  private adapters;
12
- constructor();
13
+ private userConfig?;
14
+ constructor(userConfig?: ClavixConfig);
13
15
  /**
14
16
  * Register a new agent adapter
15
17
  */
@@ -15,18 +15,20 @@ import { IntegrationError } from '../types/errors.js';
15
15
  */
16
16
  export class AgentManager {
17
17
  adapters = new Map();
18
- constructor() {
18
+ userConfig;
19
+ constructor(userConfig) {
20
+ this.userConfig = userConfig;
19
21
  // Register special adapters (require custom logic)
20
- this.registerAdapter(new ClaudeCodeAdapter()); // Doc injection
21
- this.registerAdapter(new GeminiAdapter()); // TOML format
22
- this.registerAdapter(new QwenAdapter()); // TOML format
23
- this.registerAdapter(new LlxprtAdapter()); // TOML format
22
+ this.registerAdapter(new ClaudeCodeAdapter(userConfig)); // Doc injection
23
+ this.registerAdapter(new GeminiAdapter(userConfig)); // TOML format
24
+ this.registerAdapter(new QwenAdapter(userConfig)); // TOML format
25
+ this.registerAdapter(new LlxprtAdapter(userConfig)); // TOML format
24
26
  // Register simple adapters from config (using UniversalAdapter factory)
25
27
  for (const config of getSimpleAdapters()) {
26
28
  // Skip adapters that have special handlers registered above
27
29
  if (this.adapters.has(config.name))
28
30
  continue;
29
- this.registerAdapter(new UniversalAdapter(config));
31
+ this.registerAdapter(new UniversalAdapter(config, userConfig));
30
32
  }
31
33
  }
32
34
  /**
@@ -274,7 +274,7 @@ Result: Project permanently deleted
274
274
 
275
275
  ---
276
276
 
277
- ## Agent Transparency (v5.8.2)
277
+ ## Agent Transparency (v5.9.1)
278
278
 
279
279
  ### Agent Manual (Universal Protocols)
280
280
  {{INCLUDE:agent-protocols/AGENT_MANUAL.md}}
@@ -524,7 +524,7 @@ I'll explain what's wrong and what you might need to do:
524
524
 
525
525
  ---
526
526
 
527
- ## Agent Transparency (v5.8.2)
527
+ ## Agent Transparency (v5.9.1)
528
528
 
529
529
  ### Agent Manual (Universal Protocols)
530
530
  {{INCLUDE:agent-protocols/AGENT_MANUAL.md}}
@@ -524,7 +524,7 @@ Wait for the user to decide what to do next.
524
524
 
525
525
  ---
526
526
 
527
- ## Agent Transparency (v5.8.2)
527
+ ## Agent Transparency (v5.9.1)
528
528
 
529
529
  ### Agent Manual (Universal Protocols)
530
530
  {{INCLUDE:agent-protocols/AGENT_MANUAL.md}}
@@ -107,30 +107,37 @@ Implementation: BLOCKED - I will create the plan, not the code
107
107
  - Check `.clavix/outputs/<project-name>/` for `full-prd.md`, `quick-prd.md`, etc.
108
108
  - If missing, check legacy `.clavix/outputs/summarize/`.
109
109
  2. **Read PRD**: Ingest the requirements.
110
+ 3. **Extract Architecture**: Look for the "Architecture & Design" section. Note any specific patterns (e.g., Clean Architecture, Feature-Sliced Design) or structural decisions.
110
111
 
111
112
  #### **Phase 3: Task Generation**
112
- 1. **Synthesize**: Combine [PRD Requirements] + [Codebase Patterns].
113
- 2. **Draft Tasks**: Create tasks that specify *exactly* what to change in the code.
114
- 3. **Create `tasks.md`**: Use the format in "Task Format Reference".
115
- 4. **Save to**: `.clavix/outputs/[project-name]/tasks.md`.
113
+ 1. **Synthesize**: Combine [PRD Requirements] + [Codebase Patterns] + [Architecture Decisions].
114
+ 2. **Prioritize Structure**: Ensure initial tasks cover any necessary architectural setup (e.g., creating folders for new layers, setting up base classes).
115
+ 3. **Draft Tasks**: Create tasks that specify *exactly* what to change in the code.
116
+ 4. **Create `tasks.md`**: Use the format in "Task Format Reference".
117
+ 5. **Save to**: `.clavix/outputs/[project-name]/tasks.md`.
116
118
 
117
119
  ### Part B: Behavioral Guidance (Technical Specificity)
118
120
 
119
121
  **Your goal is "Low-Level Engineering Plans", not "High-Level Management Plans".**
120
122
 
121
- 1. **Specific File Paths**:
123
+ 1. **Architecture First**:
124
+ - If the PRD specifies a pattern (e.g., Repository), the first tasks MUST set up that structure.
125
+ - **Bad**: "Implement user feature."
126
+ - **Good**: "Create `src/repositories/UserRepository.ts` interface first, then implementation."
127
+
128
+ 2. **Specific File Paths**:
122
129
  - **Bad**: "Create a user profile component."
123
130
  - **Good**: "Create `src/components/user/UserProfile.tsx`. Export as default."
124
131
 
125
- 2. **Technical Constraints**:
132
+ 3. **Technical Constraints**:
126
133
  - **Bad**: "Add validation."
127
134
  - **Good**: "Use `zod` schema in `src/schemas/user.ts`. Integrate with `react-hook-form`."
128
135
 
129
- 3. **Respect Existing Architecture**:
136
+ 4. **Respect Existing Architecture**:
130
137
  - If the project uses a `services/` folder for API calls, do **not** put `fetch` calls directly in components.
131
138
  - If the project uses `shadcn/ui`, instruct to use those primitives, not raw HTML.
132
139
 
133
- 4. **Granularity**:
140
+ 5. **Granularity**:
134
141
  - Each task should be a single logical unit of work (approx. 20-40 mins).
135
142
  - Separate "Backend API" from "Frontend UI" tasks.
136
143
  - Separate "Type Definition" from "Implementation" if complex.
@@ -150,6 +157,7 @@ Implementation: BLOCKED - I will create the plan, not the code
150
157
 
151
158
  ## Technical Context & Standards
152
159
  *Detected Stack & Patterns*
160
+ - **Architecture**: {e.g., Feature-Sliced Design, Monolith}
153
161
  - **Framework**: {e.g., Next.js 14 App Router}
154
162
  - **Styling**: {e.g., Tailwind CSS + shadcn/ui}
155
163
  - **State**: {e.g., Zustand (stores in /src/store)}
@@ -221,7 +229,7 @@ Present the plan and ask:
221
229
 
222
230
  ---
223
231
 
224
- ## Agent Transparency (v5.8.2)
232
+ ## Agent Transparency (v5.9.1)
225
233
 
226
234
  ### Agent Manual (Universal Protocols)
227
235
  {{INCLUDE:agent-protocols/AGENT_MANUAL.md}}
@@ -125,6 +125,11 @@ Both documents are automatically validated for quality (Clarity, Structure, Comp
125
125
  - "Are there performance requirements (load time, concurrent users)?"
126
126
  - **If "I don't know"**: Suggest common stacks based on project type or skip
127
127
 
128
+ **Question 3.5**: Any specific architectural patterns or design choices?
129
+
130
+ - **Optional**
131
+ - **Prompt**: "Do you have preferences for folder structure, design patterns (e.g., Repository, Adapter), or architectural style (Monolith vs Microservices)?"
132
+
128
133
  **Question 4**: What is explicitly OUT of scope? (What are we NOT building?)
129
134
 
130
135
  - **Validation**: At least 1 explicit exclusion
@@ -136,7 +141,7 @@ Both documents are automatically validated for quality (Clarity, Structure, Comp
136
141
 
137
142
  **Question 5**: Any additional context or requirements?
138
143
 
139
- - **Optional**: Press Enter to skip
144
+ - **Optional**
140
145
  - **Helpful areas**: Compliance needs, accessibility, localization, deadlines, team constraints
141
146
 
142
147
  2. **Before proceeding to document generation**, verify minimum viable answers:
@@ -161,6 +166,9 @@ Both documents are automatically validated for quality (Clarity, Structure, Comp
161
166
  ### Technical Requirements
162
167
  [User's answer to Q3, detailed]
163
168
 
169
+ ### Architecture & Design
170
+ [User's answer to Q3.5 if provided]
171
+
164
172
  ## Out of Scope
165
173
  [User's answer to Q4]
166
174
 
@@ -346,7 +354,7 @@ The validation ensures generated PRDs are immediately usable for AI consumption
346
354
 
347
355
  ---
348
356
 
349
- ## Agent Transparency (v5.8.2)
357
+ ## Agent Transparency (v5.9.1)
350
358
 
351
359
  ### Agent Manual (Universal Protocols)
352
360
  {{INCLUDE:agent-protocols/AGENT_MANUAL.md}}
@@ -415,7 +415,7 @@ I'll update the PRD and add this to the refinement history. Confirm?
415
415
 
416
416
  ---
417
417
 
418
- ## Agent Transparency (v5.8.2)
418
+ ## Agent Transparency (v5.9.1)
419
419
 
420
420
  ### Agent Manual (Universal Protocols)
421
421
  {{INCLUDE:agent-protocols/AGENT_MANUAL.md}}
@@ -98,6 +98,7 @@ Implementation: BLOCKED - I will ask questions and explore needs, not implement
98
98
  2. As the user describes their needs:
99
99
  - Ask clarifying questions about unclear points
100
100
  - Probe for technical constraints
101
+ - Probe for architectural preferences (e.g., 'Do you need a specific structure like Clean Architecture, Microservices, or Feature-Sliced Design?')
101
102
  - Explore edge cases and requirements
102
103
  - Help them think through user needs
103
104
  - Identify potential challenges
@@ -117,6 +118,7 @@ Implementation: BLOCKED - I will ask questions and explore needs, not implement
117
118
  - Target users
118
119
  - Core features
119
120
  - Technical requirements
121
+ - Architecture & Design
120
122
  - Success criteria
121
123
  - Constraints and scope
122
124
 
@@ -228,7 +230,7 @@ The goal is natural exploration of requirements, not a rigid questionnaire. Foll
228
230
 
229
231
  ---
230
232
 
231
- ## Agent Transparency (v5.8.2)
233
+ ## Agent Transparency (v5.9.1)
232
234
 
233
235
  ### Agent Manual (Universal Protocols)
234
236
  {{INCLUDE:agent-protocols/AGENT_MANUAL.md}}
@@ -115,6 +115,7 @@ Implementation: BLOCKED - I will extract requirements, not implement them
115
115
  - **Problem/Goal** [confidence]: What is the user trying to build or solve?
116
116
  - **Key Requirements** [confidence per requirement]: What features and functionality were discussed?
117
117
  - **Technical Constraints** [confidence]: Any technologies, integrations, or performance needs?
118
+ - **Architecture & Design** [confidence]: Any specific patterns, structures, or design choices?
118
119
  - **User Needs** [confidence]: Who are the end users and what do they need?
119
120
  - **Success Criteria** [confidence]: How will success be measured?
120
121
  - **Context** [confidence]: Any important background or constraints?
@@ -197,6 +198,11 @@ Implementation: BLOCKED - I will extract requirements, not implement them
197
198
  - **Integrations:** [External systems]
198
199
  - **Other:** [Any other technical constraints]
199
200
 
201
+ ## Architecture & Design
202
+ - **Pattern:** [e.g. Monolith, Microservices, Serverless]
203
+ - **Structure:** [e.g. Feature-based, Layered, Clean Architecture]
204
+ - **Key Decisions:** [Specific design choices made]
205
+
200
206
  ## User Context
201
207
  **Target Users:** [Who will use this?]
202
208
  **Primary Use Case:** [Main problem being solved]
@@ -403,7 +409,7 @@ The `/clavix:summarize` command extracts requirements from exploratory conversat
403
409
 
404
410
  ---
405
411
 
406
- ## Agent Transparency (v5.8.2)
412
+ ## Agent Transparency (v5.9.1)
407
413
 
408
414
  ### Agent Manual (Universal Protocols)
409
415
  {{INCLUDE:agent-protocols/AGENT_MANUAL.md}}
@@ -123,7 +123,7 @@ Implementation: BLOCKED - I'll analyze and report, not modify or fix
123
123
 
124
124
  ----
125
125
 
126
- ## Agent Transparency (v5.8.2)
126
+ ## Agent Transparency (v5.9.1)
127
127
 
128
128
  ### Agent Manual (Universal Protocols)
129
129
  {{INCLUDE:agent-protocols/AGENT_MANUAL.md}}
@@ -7,7 +7,9 @@ export interface ClavixConfig {
7
7
  templates: TemplateConfig;
8
8
  outputs: OutputConfig;
9
9
  preferences: PreferencesConfig;
10
- experimental?: Record<string, unknown>;
10
+ experimental?: Record<string, unknown> & {
11
+ integrationPaths?: IntegrationPathsConfig;
12
+ };
11
13
  }
12
14
  /**
13
15
  * Legacy config format (pre-v3.5.0)
@@ -37,6 +39,13 @@ export interface PreferencesConfig {
37
39
  autoOpenOutputs: boolean;
38
40
  verboseLogging: boolean;
39
41
  }
42
+ /**
43
+ * Custom directory paths for integrations
44
+ * Maps integration name (e.g., 'codex') to custom directory path
45
+ */
46
+ export interface IntegrationPathsConfig {
47
+ [integrationName: string]: string;
48
+ }
40
49
  export declare const DEFAULT_CONFIG: ClavixConfig;
41
50
  /**
42
51
  * Migrate legacy config to current format (v3.5.0+)
@@ -0,0 +1,28 @@
1
+ /**
2
+ * Path resolution utility for integration directories
3
+ *
4
+ * Supports environment variable overrides with proper priority:
5
+ * 1. Environment variable (e.g., $CODEX_HOME)
6
+ * 2. User config override (experimental.integrationPaths)
7
+ * 3. Built-in default from integrations.json
8
+ */
9
+ import type { ClavixConfig } from '../types/config.js';
10
+ import type { AdapterConfig } from '../types/adapter-config.js';
11
+ /**
12
+ * Mapping of integration names to their environment variable names
13
+ *
14
+ * Future extensibility: Add more integrations here as needed
15
+ */
16
+ export declare const ENV_VAR_MAP: Record<string, string>;
17
+ /**
18
+ * Resolves the directory path for an integration based on priority:
19
+ * 1. Environment variable (highest priority)
20
+ * 2. User config override
21
+ * 3. Built-in default (fallback)
22
+ *
23
+ * @param config - The adapter configuration from integrations.json
24
+ * @param userConfig - The user's Clavix config (optional)
25
+ * @returns The resolved directory path with tilde expansion
26
+ */
27
+ export declare function resolveIntegrationPath(config: AdapterConfig, userConfig?: ClavixConfig): string;
28
+ //# sourceMappingURL=path-resolver.d.ts.map
@@ -0,0 +1,57 @@
1
+ /**
2
+ * Path resolution utility for integration directories
3
+ *
4
+ * Supports environment variable overrides with proper priority:
5
+ * 1. Environment variable (e.g., $CODEX_HOME)
6
+ * 2. User config override (experimental.integrationPaths)
7
+ * 3. Built-in default from integrations.json
8
+ */
9
+ import * as os from 'os';
10
+ /**
11
+ * Mapping of integration names to their environment variable names
12
+ *
13
+ * Future extensibility: Add more integrations here as needed
14
+ */
15
+ export const ENV_VAR_MAP = {
16
+ codex: 'CODEX_HOME',
17
+ // Future: cursor: 'CURSOR_HOME',
18
+ // Future: gemini: 'GEMINI_HOME',
19
+ };
20
+ /**
21
+ * Resolves the directory path for an integration based on priority:
22
+ * 1. Environment variable (highest priority)
23
+ * 2. User config override
24
+ * 3. Built-in default (fallback)
25
+ *
26
+ * @param config - The adapter configuration from integrations.json
27
+ * @param userConfig - The user's Clavix config (optional)
28
+ * @returns The resolved directory path with tilde expansion
29
+ */
30
+ export function resolveIntegrationPath(config, userConfig) {
31
+ const integrationName = config.name;
32
+ // Priority 1: Environment variable
33
+ const envVar = ENV_VAR_MAP[integrationName];
34
+ if (envVar && process.env[envVar]) {
35
+ return process.env[envVar];
36
+ }
37
+ // Priority 2: User config override
38
+ const customPath = userConfig?.experimental?.integrationPaths?.[integrationName];
39
+ if (customPath && typeof customPath === 'string') {
40
+ return expandTilde(customPath);
41
+ }
42
+ // Priority 3: Built-in default from config
43
+ return expandTilde(config.directory);
44
+ }
45
+ /**
46
+ * Expands tilde (~) to the user's home directory
47
+ *
48
+ * @param dir - Directory path that may start with ~/
49
+ * @returns Directory path with ~ expanded to home directory
50
+ */
51
+ function expandTilde(dir) {
52
+ if (dir.startsWith('~/')) {
53
+ return dir.replace('~', os.homedir());
54
+ }
55
+ return dir;
56
+ }
57
+ //# sourceMappingURL=path-resolver.js.map
@@ -119,7 +119,6 @@ export declare const IntegrationsConfigSchema: z.ZodObject<{
119
119
  placeholder?: string | undefined;
120
120
  }[]>;
121
121
  }, "strip", z.ZodTypeAny, {
122
- version: string;
123
122
  integrations: {
124
123
  name: string;
125
124
  directory: string;
@@ -134,9 +133,9 @@ export declare const IntegrationsConfigSchema: z.ZodObject<{
134
133
  global?: boolean | undefined;
135
134
  placeholder?: string | undefined;
136
135
  }[];
136
+ version: string;
137
137
  $schema?: string | undefined;
138
138
  }, {
139
- version: string;
140
139
  integrations: {
141
140
  name: string;
142
141
  directory: string;
@@ -151,8 +150,14 @@ export declare const IntegrationsConfigSchema: z.ZodObject<{
151
150
  global?: boolean | undefined;
152
151
  placeholder?: string | undefined;
153
152
  }[];
153
+ version: string;
154
154
  $schema?: string | undefined;
155
155
  }>;
156
+ /**
157
+ * Schema for integration paths in experimental config
158
+ * Maps integration name to custom directory path
159
+ */
160
+ export declare const IntegrationPathsSchema: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
156
161
  /**
157
162
  * Schema for user's .clavix/config.json
158
163
  * Matches ClavixConfig interface in src/types/config.ts
@@ -194,11 +199,17 @@ export declare const UserConfigSchema: z.ZodObject<{
194
199
  autoOpenOutputs: boolean;
195
200
  verboseLogging: boolean;
196
201
  }>>;
197
- experimental: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
202
+ experimental: z.ZodOptional<z.ZodObject<{
203
+ integrationPaths: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
204
+ }, "passthrough", z.ZodTypeAny, z.objectOutputType<{
205
+ integrationPaths: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
206
+ }, z.ZodTypeAny, "passthrough">, z.objectInputType<{
207
+ integrationPaths: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
208
+ }, z.ZodTypeAny, "passthrough">>>;
198
209
  }, "strip", z.ZodTypeAny, {
199
- version?: string | undefined;
200
- integrations?: string[] | undefined;
201
210
  providers?: string[] | undefined;
211
+ integrations?: string[] | undefined;
212
+ version?: string | undefined;
202
213
  templates?: {
203
214
  prdQuestions: string;
204
215
  fullPrd: string;
@@ -212,11 +223,13 @@ export declare const UserConfigSchema: z.ZodObject<{
212
223
  autoOpenOutputs: boolean;
213
224
  verboseLogging: boolean;
214
225
  } | undefined;
215
- experimental?: Record<string, unknown> | undefined;
226
+ experimental?: z.objectOutputType<{
227
+ integrationPaths: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
228
+ }, z.ZodTypeAny, "passthrough"> | undefined;
216
229
  }, {
217
- version?: string | undefined;
218
- integrations?: string[] | undefined;
219
230
  providers?: string[] | undefined;
231
+ integrations?: string[] | undefined;
232
+ version?: string | undefined;
220
233
  templates?: {
221
234
  prdQuestions: string;
222
235
  fullPrd: string;
@@ -230,7 +243,9 @@ export declare const UserConfigSchema: z.ZodObject<{
230
243
  autoOpenOutputs: boolean;
231
244
  verboseLogging: boolean;
232
245
  } | undefined;
233
- experimental?: Record<string, unknown> | undefined;
246
+ experimental?: z.objectInputType<{
247
+ integrationPaths: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
248
+ }, z.ZodTypeAny, "passthrough"> | undefined;
234
249
  }>;
235
250
  /**
236
251
  * Inferred TypeScript types from schemas
@@ -63,6 +63,21 @@ const PreferencesConfigSchema = z.object({
63
63
  autoOpenOutputs: z.boolean(),
64
64
  verboseLogging: z.boolean(),
65
65
  });
66
+ /**
67
+ * Schema for integration paths in experimental config
68
+ * Maps integration name to custom directory path
69
+ */
70
+ export const IntegrationPathsSchema = z
71
+ .record(z.string().min(1, 'Integration name is required'), z.string().min(1, 'Path cannot be empty'))
72
+ .optional();
73
+ /**
74
+ * Schema for experimental configuration
75
+ */
76
+ const ExperimentalConfigSchema = z
77
+ .object({
78
+ integrationPaths: IntegrationPathsSchema,
79
+ })
80
+ .passthrough(); // Allow other experimental fields
66
81
  /**
67
82
  * Schema for user's .clavix/config.json
68
83
  * Matches ClavixConfig interface in src/types/config.ts
@@ -78,7 +93,7 @@ export const UserConfigSchema = z.object({
78
93
  templates: TemplateConfigSchema.optional(),
79
94
  outputs: OutputConfigSchema.optional(),
80
95
  preferences: PreferencesConfigSchema.optional(),
81
- experimental: z.record(z.unknown()).optional(),
96
+ experimental: ExperimentalConfigSchema.optional(),
82
97
  });
83
98
  /**
84
99
  * Validate integrations.json content (build-time, strict)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "clavix",
3
- "version": "5.8.2",
3
+ "version": "5.9.1",
4
4
  "description": "Agentic-first prompt workflows. Markdown templates that teach AI agents how to optimize prompts, create PRDs, and manage implementation.\n\nSLASH COMMANDS (in your AI assistant):\n /clavix:improve Optimize prompts with auto-depth\n /clavix:prd Generate PRD through questions\n /clavix:plan Create task breakdown from PRD\n /clavix:implement Execute tasks with progress tracking\n /clavix:start Begin conversational session\n /clavix:summarize Extract requirements from conversation\n /clavix:refine Refine existing PRD or prompt\n /clavix:verify Verify implementation against requirements\n /clavix:archive Archive completed projects\n\nWorks with Claude Code, Cursor, Windsurf, and 20 AI coding tools.",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -70,6 +70,7 @@
70
70
  "@oclif/core": "^4.8.0",
71
71
  "@oclif/plugin-help": "^6.2.35",
72
72
  "chalk": "^5.6.2",
73
+ "clavix": "^5.9.0",
73
74
  "fs-extra": "^11.3.2",
74
75
  "inquirer": "^12.11.1",
75
76
  "zod": "^3.24.4"