Add a cascading configuration system to ferix-code CLI that allows users to define default CLI options in configuration files.
Config Priority (highest to lowest):
- CLI arguments (always override everything)
.ferix/config.jsonferix.jsonpackage.jsonunderferixkey
Supported Options: iterations, verify, branch, push, pr, provider
Excluded: task (always passed via CLI)
Effect schema for config file validation:
import { Schema as S } from "effect";
import { ProviderNameSchema } from "./config.js";
export const FileConfigSchema = S.Struct({
iterations: S.optional(S.Number),
verify: S.optional(S.Array(S.String)),
branch: S.optional(S.String),
push: S.optional(S.Boolean),
pr: S.optional(S.Boolean),
provider: S.optional(ProviderNameSchema),
});
export type FileConfig = typeof FileConfigSchema.Type;
export const decodeFileConfig = S.decodeUnknown(FileConfigSchema);Service interface for config loading:
export interface ConfigLoaderService {
readonly load: () => Effect.Effect<FileConfig, ConfigLoadError>;
}
export class ConfigLoader extends Context.Tag("@ferix/ConfigLoader")<
ConfigLoader,
ConfigLoaderService
>() {}Cascading config loader implementation that:
- Reads
.ferix/config.json,ferix.json, andpackage.json - Validates with Effect schema
- Merges configs (higher priority wins)
- Returns empty config if no files exist (not an error)
Memory implementation for testing.
Add ConfigLoadError:
export class ConfigLoadError extends Data.TaggedError("ConfigLoadError")<{
readonly message: string;
readonly path: string;
readonly cause?: unknown;
}> {}Add to FerixError union.
Export new schema: export * from "./file-config.js";
Export service: export { ConfigLoader, type ConfigLoaderService } from "./config-loader.js";
Export layer: export { FileSystemConfig } from "./config/file-system.js";
Modify CLI entry point to:
- Load config before action
- Merge CLI args over config (CLI wins)
- Handle CLI defaults properly (don't override config when CLI uses default)
Key merge logic:
// CLI args override config, but check for explicit vs default values
const config: LoopConfig = {
task,
maxIterations: cliOptions.iterations !== "1"
? Number.parseInt(cliOptions.iterations, 10)
: fileConfig.iterations ?? 1,
verifyCommands: cliOptions.verify ?? fileConfig.verify ?? [],
branch: cliOptions.branch ?? fileConfig.branch,
push: cliOptions.push ?? fileConfig.push,
pr: cliOptions.pr ?? fileConfig.pr,
provider: cliOptions.provider !== "claude"
? cliOptions.provider as ProviderName
: fileConfig.provider ?? "claude",
};Add section after "Deployment" documenting:
- Config file locations and priority
- Example
ferix.json - Example
package.jsonwith ferix key - All available options with types
Add two new DocCells after CLI Options section:
- Configuration: Example ferix.json with common options
- Config Locations: Priority list with descriptions
Add translations under code.docs:
{
"config": "Configuration",
"configDesc": "Create a ferix.json file to set default options",
"configLocations": "Config Locations",
"configLocationsDesc": "Files are checked in priority order (CLI args override all)",
"config_priority1": "Highest priority",
"config_priority2": "Project root",
"config_priority3": "Lowest priority"
}- Create
file-config.tsschema - Add
ConfigLoadErrorto errors.ts - Create
config-loader.tsservice interface - Implement
layers/config/file-system.ts - Create
layers/config/memory.tsfor testing - Update all index.ts exports
- Modify CLI entry point (
index.ts) - Update README.md
- Update CodeDocs component
- Add translations
- Unit tests: Config loader with various file combinations
- Manual testing:
- Create
ferix.jsonwithiterations: 5- verify it's used - Run with
-i 3- verify CLI overrides config - Add
ferixkey to package.json - verify lowest priority - Create
.ferix/config.json- verify highest priority
- Create
- Run linting:
bun lint && bun format - Web docs: Check
/coderoute renders new config section
apps/code/src/domain/schemas/config.ts- Existing schemas to referenceapps/code/src/domain/errors.ts- Error pattern to followapps/code/src/layers/session/file-system.ts- File I/O pattern with Effectpackages/ui/src/components/code/code-docs.tsx- Docs component structure