`company_skills.markdown` stored the full SKILL.md body. The on-disk
file under `profile/skills/{companyId}/{slug}/SKILL.md` is what pi-
coding-agent actually reads via `loadSkills` at runtime. The DB column
was a duplicate — import wrote to both, renderer read from DB. Any
discrepancy between disk and DB was invisible until the agent behaved
differently from what the user saw in SkillDetail.
Disk becomes the single source of truth. DB keeps name / description /
metadata / source info / file inventory — the cheap lookup row. UI reads
SKILL.md content live via a new IPC channel.
## Migration v37 (rebuild company_skills without markdown)
Table-rebuild pattern matching v35/v36: `fn:` form, PRAGMA walk for
drift columns, row-count assertion before DROP, `defer_foreign_keys`
for the `agent_skill_assignments(skill_id)` reference. Indexes
recreated. Idempotent via `schema_migrations` ledger.
Existing DB rows' markdown content is discarded — but the on-disk
SKILL.md files are the authoritative copy, so no user-visible data
loss. Any agent using those skills keeps working; the UI just starts
reading from disk instead of the DB cache.
## Code changes
- `src/main/database/skills.ts`: drop `markdown` from read mapping,
upsert input type, INSERT column/bind list, ON CONFLICT DO UPDATE.
- `src/shared/types/records-core.ts`: `SkillRecord.markdown` removed.
- `src/main/skills/import.ts` + `import-github.ts`: drop `markdown:`
from 4 `saveCompanySkill` call sites. Disk-write via
`materializeSkillFiles` unchanged (it's what the file agent reads).
- `src/main/skills/index.ts`: expose `skillFilesDir` for the new IPC
handler to resolve `${profile}/skills/${companyId}/${slug}/SKILL.md`.
- `src/shared/contracts/channels.ts` + `schemas-execution.ts` +
`desktop-api/skills.ts`: new `getSkillMarkdown` channel
`{ companyId, slug } → DesktopResult<string>`.
- `src/preload/index.ts`: expose `getSkillMarkdown(companyId, slug)`.
- `src/main/ipc-skill-handlers.ts`: handler validates schema, ensures
company, resolves path, `readFile`, returns content. Fails closed
with `SKILL_NOT_FOUND` on ENOENT, `SKILL_READ_FAILED` on other
read errors.
- `src/renderer/components/skills/SkillDetail.tsx`: `useEffect` fetches
markdown via IPC when the skill detail loads; shows "Loading…" until
resolved, surfaces read errors. Preserves `stripFrontmatter`.
- Tests: drop `markdown:` from 2 fixture sites
(`skill-types.test.ts`, `skill-aware-assignment.spec.ts`).
## Verification
- typecheck / lint / 578 tests green
- `grep 'skill\.markdown' src/` → 0 DB-record reads
- `grep '\.markdown\b' src/main/database/skills.ts` → 0
- Remaining `.markdown` references are all `ghSkill.markdown` (GitHub
fetcher's intermediate struct feeding `materializeSkillFiles` to
disk) and parameter names in `stripFrontmatter(markdown: string)` /
fs-writer helpers — none read from a DB row.
Handlers for deleteTask/deleteGoal/deleteProject live in
ipc-core-task-graph-handlers.ts:166-168 (backed by
database/tasks-crud.ts and database/entity-crud.ts), and
deleteWorkspace lives at line 169 (backed by database/workspaces.ts).
The four @planned comments were misleading.
- Create ipc-budget-handlers.ts with 6 budget channel handlers (save/delete/list policies, list/resolve incidents, get status)
- Add budgetService to RegisterDomainHandlersDependencies interface
- Register budget handlers in ipc-domain-handlers.ts composition
- Add BudgetEnforcementService lazy slot in service-graph.ts with getOrCreateBudgetEnforcementService
- Pass budgetService to domain handler registration in main-runtime-support.ts
- Fix preload bridge to pass {companyId} object for listBudgetPolicies and getBudgetStatus
- D-06: checkAutoResolve called on saveBudgetPolicy to auto-resolve incidents on limit increase
- Add releaseTaskLock to worker crash recovery after finishRun (EXEC-02)
- Track affected agent company IDs for targeted wake promotion
- Replace listWakeupRequests+loop with promoteWakeupRequests+wakeAgentIfPossible in run completion
- Track hadDeferredWakes flag for circuit breaker self-wake decision
- Add listWakeupRequests IPC channel to IPC_CHANNELS
- Add wakeupQuerySchema with Zod validation and WakeupRequestRecord interface
- Add listWakeupRequests to DesktopApi type
- Add listWakeupRequests preload bridge method
- Add registerHandle for listWakeupRequests IPC handler with company validation
- Add listSkillAgents and listAgentSkills IPC channels with Zod schemas
- Create SkillDetail component with metadata, file viewer, update check, delete
- Create SkillAgentToggles with discriminated union for skill/agent-centric modes
- Wire SkillDetail into SkillsSection right column replacing placeholder
- Remove duplicate skill method declarations from DesktopApi type
- Add searchMessages method to AppDatabase with LIKE query, wildcard escaping, channel scoping, ORDER BY created_at DESC with limit
- Add searchMessages IPC channel and searchMessagesSchema to contracts.ts
- Register IPC handler in ipc-agent-coordination-handlers.ts with Zod validation
- Wire searchMessages through preload bridge
- Add 8 unit tests covering body/subject search, wildcard escaping, channel scoping, empty results, limit, and ordering