Configuration and CLI Option Types
Relevant Source Files
This page details the technical implementation of the PALEE configuration system and the TypeScript interfaces governing CLI command options. The configuration system manages persistent settings such as the vault location and AI preferences, while the CLI option types ensure type-safe interaction between the command-line interface and the engine core.
Configuration System
PALEE uses a JSON-based configuration file to store user preferences. The configuration is managed via the PaleeConfig interface and accessed through platform-specific paths.
PaleeConfig Interface
The PaleeConfig interface defines the core settings required for PALEE to operate src/types.ts
| Property | Type | Description |
|---|---|---|
vaultPath | string (optional) | The absolute path to the Obsidian vault containing the Markdown notes. |
aiProvider | string (optional) | The LLM provider for AI-assisted features (e.g., "openai", "anthropic"). |
model | string (optional) | The specific model identifier to use for AI tasks. |
baseUrl | string (optional) | The OpenAI-compatible endpoint of the configured provider. Set with palee config set-base-url, which applies the same gate the caller does (normalizeProviderEndpoint): http is accepted only for a loopback host, reserved address space is refused whatever the scheme (link-local including the cloud metadata address, the unspecified and multicast ranges, IPv4-mapped, NAT64, 6to4 and Teredo literals, and *.internal names), and the URL may carry no userinfo, query string or fragment. Judged by address shape, so a hostname that merely starts with digits like 169.254.example.com is not blocked. When a key is already stored, changing to a different origin (scheme, host or port) prompts on a terminal unless --keep-key is passed; a non-interactive or --json run refuses with exit 2 without it. |
apiKey | string (optional) | The provider credential. Stored as plaintext at rest, never printed by any command, and accepted only from --from-env, a pipe, or a prompt — never from argv, which other processes can read. |
Config File Resolution
The location of config.json is determined by the getConfigPath function src/cli/config.ts which follows platform-specific conventions:
- Environment Override: If the
PALEE_CONFIG_DIRenvironment variable is set, the config is stored in${PALEE_CONFIG_DIR}/config.jsonsrc/cli/config.ts This is primarily used for test isolation test/cli-commands.test.ts - Windows:
%LOCALAPPDATA%\palee\config.jsonsrc/cli/config.ts - POSIX (Linux/macOS):
~/.config/palee/config.jsonsrc/cli/config.ts
Configuration Flow
The loadConfig function reads the JSON file and returns a PaleeConfig object. If the file does not exist (ENOENT), it returns an empty object src/cli/config.ts Keys are admitted one at a time and only when their value is a string, so a hand-edited apiKey: 20240115 is dropped rather than carried as a credential. The saveConfig function ensures the directory exists before writing the updated configuration back to disk src/cli/config.ts Because the file can hold a provider credential, the temp file is opened 0600 inside a 0700 directory before any byte is written, and the atomic rename carries that mode onto config.json — including for a file that predates the credential field. Windows ignores the mode and resolves access through the directory ACL, so the 0600/0700 modes are not a guarantee there. Instead, set-api-key refuses on Windows to store the key when the resolved config directory is outside the user's profile roots (%USERPROFILE% / %LOCALAPPDATA%): isConfigDirStorableForKey compares the directory to those roots with path.win32.relative, so a share or synced folder whose inherited ACL may expose the key is rejected rather than written to. The refusal names the directory and points at the PALEE_API_KEY runtime variable or the PALEE_ALLOW_INSECURE_CONFIG_DIR=1 override. This is a location heuristic, not an ACL read; a legitimately secured non-profile directory is refused unless overridden.
palee config show --json emits the configuration as a single JSON object with vault_path, ai_provider, base_url, model, and a boolean api_key_set. The credential itself has no field in that output: the boolean reports only whether a key is stored, so redirecting config show into a tool can never leak the key.
--json is not confined to show — every action in the command answers machine-readable output, because a script that opted into JSON must never have to parse a sentence to learn whether its write landed. A successful set-vault, set-provider, set-base-url, set-model or set-api-key prints {status: "set", <the field it wrote>} on stdout at exit 0, and unset-api-key prints {status: "unset"} or {status: "absent"} with api_key_set: false. test-connection answers one object carrying reachable, endpoint, model, key_source, reply, latency_ms and tokens. Every refusal puts {error} on stderr at exit 2; where the human form printed a second guidance line the object carries it as remedy, and an unknown action lists valid_actions. A set-base-url refusal for an origin change with a stored key carries {error, remedy} and leaves both the old URL and the key on disk. key_source names which source won (env / config / none) rather than any part of the value.
Sources:
Difficulty Normalization
The Difficulty type is a union of 'beginner', 'intermediate', and 'advanced'src/types.ts Because users may provide difficulty levels as numbers (1-5) or varied strings, the system employs a normalizeDifficulty function src/types.ts
Mapping Logic
- Numbers: 1 maps to
beginner; 2-3 maps tointermediate; 4-5 maps toadvancedsrc/types.ts - Strings: Case-insensitive matching for canonical names. Stringified numbers are parsed and mapped using the number logic src/types.ts
- Fallback: Defaults to
intermediatefor null, undefined, or invalid inputs src/types.ts
Sources:
CLI Option Interfaces
Each CLI command has a corresponding TypeScript interface that defines its accepted flags and arguments. This ensures that the command handlers receive correctly typed data from the CLI entry point.
Command Option Summary
| Interface | Command | Properties |
|---|---|---|
AdoptOptions | palee adopt | difficulty (Difficulty), dependsOn (string) src/types.ts |
NextOptions | palee next | all (boolean), json (boolean) src/types.ts |
PlanOptions | palee plan | json (boolean) src/types.ts |
DashboardOptions | palee dashboard | json (boolean) src/types.ts |
ProgressOptions | palee progress | topic (string), json (boolean) src/types.ts |
ValidateOptions | palee validate | fix (boolean), json (boolean), strict (boolean) src/types.ts |
RoadmapOptions | palee roadmap | from (string), yes (boolean) src/types.ts |
SessionOptions | palee session | interactive (boolean), topic (string), json (boolean) src/types.ts |
UpdateOptions | palee update | dryRun (boolean) |
Implementation Detail: Adopt Command
The adoptCommand utilizes AdoptOptions to initialize a note's frontmatter. It validates that the difficulty provided matches valid inputs (beginner, intermediate, advanced, or 1-5) before calling normalizeDifficultysrc/cli/adopt.ts
Sources:
Data Flow Diagrams
Configuration and File Resolution
This diagram bridges the natural language concept of "Platform Specific Config" to the code entities responsible for resolving paths and loading data.
Sources:
Command Option Processing
This diagram illustrates how CLI inputs are transformed into typed options and then into vault modifications, using the adopt command as an example.
Sources:
