Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 19 additions & 3 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,23 @@

All notable changes to this project will be documented in this file.

## [0.1.0] - Phase 1 Release
## [Unreleased]

### Added
- **Machine-Readable `--json` Output (Invariant #45)**: Added `--json` option across all reading commands (`next`, `plan`, `progress`, `dashboard`, `validate`, and `session list`). Piped or redirected output automatically defaults to JSON mode when stdout is non-TTY.
- **Structured JSON Setup Errors**: Vault validation and configuration errors emit structured `{"error": "..."}` JSON with exit code 2 when run in JSON or non-TTY mode.
- **Standardized `Difficulty` Enum & Runtime Helper**: Defined `Difficulty = 'beginner' | 'intermediate' | 'advanced'` in `src/types.ts` and added `normalizeDifficulty()` runtime helper supporting string folding, whitespace trimming, and numeric mappings (1 -> beginner, 2..3 -> intermediate, 4..5 -> advanced).
- **Empty Vault Onboarding Guidance**: Added centralized `printEmptyVaultOnboarding()` helper to provide actionable commands (`palee adopt`, `palee roadmap --from`) across empty vault states.
- **Session Topic Option**: Added `--topic <id>` option to `palee session` and implemented `resolveSessionTopic()` with active topic fallback.

### Fixed
- **Dashboard Division-by-Zero Guard**: Added explicit `total > 0` ternary check in `src/cli/dashboard.ts` to prevent `NaN%` display on empty vaults.
- **Vault Validation & Permissions**: Replaced abrupt `process.exit(0)` with clean `return` on empty states and added directory/read-permission (`R_OK`) checks at vault root.
- **Phantom Topic Elimination**: Eliminated default creation of phantom `T-general` topic notes during session operations.

---

## [0.1.0] - 2026-08-12

### Added
- Setup & Architecture with `commander`, `yaml`, and Node.js testing.
Expand All @@ -14,5 +30,5 @@ All notable changes to this project will be documented in this file.
- Interactive draft checkpoint recovery.

### Fixed
- Fixed strict TypeScript enforcement and removed all dead code (YAGNI).
- Purged all "AI-tell" narrative comments to conform to strict `senior-code` standards.
- Fixed strict TypeScript enforcement and removed all dead code.
- Purged all narrative comments to conform to strict code standards.
51 changes: 25 additions & 26 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -132,35 +132,34 @@ palee config set-vault /path/to/obsidian/vault

## Data Model

Each topic is tracked with:
Each topic note stores flat YAML frontmatter directly inside your Obsidian vault:
```yaml
---
palee_schema: 1
palee_id: T-docker-volumes
topic: Docker Volumes
track: devops
status: learning
difficulty: 2
dependencies:
title: Docker Volumes
difficulty: beginner
Comment thread
qodo-code-review[bot] marked this conversation as resolved.
depends_on:
- T-docker-basics
assessment:
conceptual: 0.85
practical: 0.70
debug: 0.60
feynman: 0.75
assessed_at: 2026-01-15
review:
interval_days: 6
repetition: 1
ease_factor: 2.36
lapses: 0
last_quality: 4
last_reviewed_at: 2026-01-15
due_at: 2026-01-21
topic_mastery: 0.725
conceptual: 0.85
practical: 0.70
debug: 0.60
feynman: 0.75
assessed_at: 2026-01-15
ease_factor: 2.36
interval_days: 6
repetition: 1
lapses: 0
last_quality: 4
last_reviewed_at: 2026-01-15
due_at: 2026-01-21
---
```

`assessment` measures understanding and is independent from `review`, which records recall quality for SM-2 scheduling. PALEE uses `not_started`, `learning`, `paused`, and `archived` as operational statuses; mastery is derived from assessment scores rather than stored as an ambiguous `completed` status.
Frontmatter stores flat keys directly for clean Obsidian parsing and fast atomic updates. Programmatic TypeScript interfaces (`Topic`) map these fields into structured conceptual and review metrics.

`topic_mastery` is derived from assessment scores (`(conceptual + practical + debug + 2*feynman) / 5`), independent from SM-2 recall scheduling. Newly adopted notes begin with `topic_mastery: 0.0` and `null` review fields.

Session memory is stored inside the connected vault:

Expand All @@ -173,13 +172,13 @@ Session memory is stored inside the connected vault:

`hot.md` is capped at 250 words and points to the latest full session. Full session notes preserve the learning history without forcing every future AI prompt to load the entire log.

See [memory_design.md](memory_design.md) for the session-memory format, lifecycle, stable IDs, and recovery rules.
See [memory_design.md](planning/memory_design.md) for the session-memory format, lifecycle, stable IDs, and recovery rules.

See [storage_design.md](storage_design.md) for frontmatter preservation, atomic writes, vault traversal, validation, and cache behavior.
See [storage_design.md](planning/storage_design.md) for frontmatter preservation, atomic writes, vault traversal, validation, and cache behavior.

See [invariants.md](invariants.md) for the acceptance-test blueprint that must pass before Phase 1 is considered complete.
See [invariants.md](planning/invariants.md) for the acceptance-test blueprint that must pass before Phase 1 is considered complete.

See [roadmap_design.md](roadmap_design.md) for the imported-roadmap and guided personalized-roadmap contracts.
See [roadmap_design.md](planning/roadmap_design.md) for the imported-roadmap and guided personalized-roadmap contracts.

## Philosophy

Expand Down Expand Up @@ -214,4 +213,4 @@ Detailed contribution guidelines will be added with the implementation source.

## License

Planned license: MIT. The license file will be added before distribution.
MIT (see [LICENSE](LICENSE)).
16 changes: 9 additions & 7 deletions agent.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,13 @@ No path aliases — plain relative imports (`'../types'`, `'./frontmatter'`). Da
## CLI conventions (from src/cli/*.ts and bin/palee.ts)

- **Adding a command** requires: a default-exported handler in `src/cli/<name>.ts`, a `.command()...action(handler)` block in `bin/palee.ts`, and a matching `*Options` type in `src/types.ts` for any flags.
- Every handler starts with `loadConfig()`; when `!config.vaultPath`, print exactly `Error: Vault path not configured. Run: palee config set-vault <path>` to stderr and `process.exit(2)`.
- Every reading handler starts with `loadConfig()` and `const vaultPath = validateVaultPath(config.vaultPath, { json: options?.json }); if (!vaultPath) return;`. On missing/invalid vault, `validateVaultPath` prints to stderr (plain text or structured JSON) and sets `process.exitCode = 2`.
- Discover notes via `walkVault` + `parseFrontmatter`; filter on `frontmatter.palee_id`. WalkVault skips dot-dirs (`.obsidian`, `.palee`, `.git`), `node_modules`, symlinks — `.palee/` is never scanned as topics.
- Wrap every handler in try/catch → `console.error(\`Error: ${err.message}\`); process.exit(5)`.
- **Exit codes are load-bearing** (README and CI assert them): `0` success, `1` partial import failure, `2` usage/config, `3` validation failures, `4` OCC lock conflict, `5` unexpected exception. Every code path calls `process.exit(n)` explicitly.
- Output style: plain `console.log`/`console.error` — **no ANSI colors, no tables, no progress bars, no emoji**. Symbols: `✓` success, `⚠` warning, `•` bullets, `─` separators, `=== ... ===` headers (boxed `╔═╗` only on dashboard), 2-space sub-detail indents, `(not set)` / `(none)` empty states, `.toFixed(1)` percentages. Always guard div-by-zero with `|| 0` before `.toFixed(1)`.
- Wrap every handler in try/catch → `console.error(\`Error: ${err.message}\`); process.exitCode = 5; return;`.
- **Exit codes are load-bearing** (README and CI assert them): `0` success, `1` partial import failure, `2` usage/config, `3` validation failures, `4` OCC lock conflict, `5` unexpected exception.
- **Standard policy**: Prefer `process.exitCode = N; return;` on success and recoverable errors so Node can cleanly flush buffered `stdout`/`stderr` streams and complete test runner cycles.
- Reserve `process.exit(5)` for unrecoverable top-level fatal exceptions.
- Output style: plain `console.log`/`console.error` — **no ANSI colors, no tables, no progress bars, no emoji**. Symbols: `✓` success, `⚠` warning, `•` bullets, `─` separators, `=== ... ===` headers (boxed `╔═╗` only on dashboard), 2-space sub-detail indents, `(not set)` / `(none)` empty states, `.toFixed(1)` percentages. Always guard division calculations with `total > 0` checks.
Comment thread
qodo-code-review[bot] marked this conversation as resolved.

## Sacred invariants (never break; all are test-pinned)

Expand All @@ -49,9 +51,9 @@ Storage (`src/storage/`):

## On-disk formats

- **Topic note frontmatter is FLAT** (not the nested `assessment`/`review` shape in `types.ts` — the type is out of sync; code reads flat keys). Order written by `adopt.ts`: `palee_id`, `palee_schema`, `difficulty`, `depends_on`, `topic_mastery`, `assessed_at`, `conceptual/practical/debug/feynman`, `ease_factor`, `interval_days`, `repetition`, `lapses`, `last_quality`, `last_reviewed_at`, `due_at`. `difficulty` is the string enum `beginner|intermediate|advanced` (despite `types.ts:27` typing it `number` — cast `as string`). `last_quality`, `last_reviewed_at`, `due_at`, `assessed_at` may be literal `null` — branch on null before `new Date(...)`, default via `|| 0`. Dates are `YYYY-MM-DD` for review/due fields; sessions/hot use full ISO with ms+Z; never assume one format.
- **Topic note frontmatter is FLAT** (not the nested `assessment`/`review` shape in `types.ts` — the type is out of sync; code reads flat keys). Order written by `adopt.ts`: `palee_id`, `palee_schema`, `difficulty`, `depends_on`, `topic_mastery`, `assessed_at`, `conceptual/practical/debug/feynman`, `ease_factor`, `interval_days`, `repetition`, `lapses`, `last_quality`, `last_reviewed_at`, `due_at`. `difficulty` is the string enum `Difficulty = 'beginner' | 'intermediate' | 'advanced'` standardized in `src/types.ts` with `normalizeDifficulty()`. `last_quality`, `last_reviewed_at`, `due_at`, `assessed_at` may be literal `null` — branch on null before `new Date(...)`, default via `|| 0`. Dates are `YYYY-MM-DD` for review/due fields; sessions/hot use full ISO with ms+Z; never assume one format.
- **`.palee/index.md`**: `palee_schema: 1`, `type: "session_index"`, `updated_at: YYYY-MM-DD`; body `# PALEE Session Index` + `Total Sessions: N` + `- [[S-<id>]] - Topic: T-x (YYYY-MM-DD)`, newest first. `.palee` metadata files quote all strings with double quotes; topic notes are unquoted.
- **Session file** `.palee/sessions/S-<id>.md`: FM `palee_schema`, `session_id`, `topic_id`, `started_at`, `ended_at`, `status: "completed"|"draft"`; body `# Session: <id>`. `topic_id` defaults to phantom `T-general` when none given (known bug — don't rely on it).
- **Session file** `.palee/sessions/S-<id>.md`: FM `palee_schema`, `session_id`, `topic_id`, `started_at`, `ended_at`, `status: "completed"|"draft"`; body `# Session: <id>`. `topic_id` requires explicit `--topic` or resolves active topic from `.palee/hot.md`.
- `parseFrontmatter` requires `---` at byte 0; a UTF-8 BOM or leading blank line silently yields `{frontmatter: null}` and skips the note everywhere. Don't "normalize" the blank line between frontmatter and body — it changes fingerprints.

## Verification loop — run before considering a change done
Expand All @@ -66,7 +68,7 @@ Tests use real temp dirs (`fs.mkdtempSync`), CLI tests spawn `npx tsx bin/palee.

## Known gaps (fix deliberately, or leave clearly marked)

- `--json` / non-TTY machine output: specified, unimplemented. Must have no ANSI, no spinners.
- `--json` and non-TTY machine output: Implemented across all 6 reading commands (`next`, `plan`, `progress`, `dashboard`, `validate`, `session list`).
- `validate --fix` and `session end` are Phase-1 stubs ("not implemented"). `migrate` is read-only and fails closed on unrecognized schemas.
- `computeTopicMastery()` does not exist — mastery stays at the value `adopt` seeds (0.0); do not invent an unblessed mastery formula. Spec formula: `round((c + p + d + 2f) / 5, 4)`; zero active topics ⇒ `global_mastery: null`, never numeric 0.
- `config set-provider` is a single-string setter; `PaleeConfig` has no `apiKey`/`baseUrl` — blocks Phase-2 AI. Never print secrets from `config show`.
Expand Down
Loading
Loading