Changelog
All notable changes to Lycato. Format: Keep a Changelog. Versioning: SemVer.
[Unreleased]
Audit remediation (2026-07-27/28), then the GTM FIX cycle (2026-07) which
closes the three build items recorded in the repository-only
gtm/GAP_REMEDIATION.md. Continuous-improvement loop notes remain below.
Added — full story and UX audit (2026-08-09)
- Exact 50-story verification ledger at
docs/testing/USER_STORY_AUDIT_2026-08-09.md, with a regression test that requires every canonical Lycato story exactly once, requires its status to match, and keeps the suite snapshot totals derived from the rows. - Generated-site link integrity gate for local files, clean URLs, rewrite routes, and fragments. Public docs can no longer ship broken internal links.
- Installed-artifact acceptance breadth in the clean-machine gate: morning,
search, JSON logs, migration dry-run, backup/restore, and a real loopback
lycato servehealth/static-page probe now run from the packed CLI.
Fixed — full story and UX audit (2026-08-09)
- Verified-email second-tab handoff now force-refreshes the Firebase ID token before protected Firestore access. A newly verified founder no longer sees a false setup pause caused by the pre-verification token cache.
- Public lead-deletion requests no longer crash after the write: their live result region now belongs to the submitting form, with a shipped-shell regression contract.
- Hosted native form validation now leaves a persistent plain-language
message,
aria-invalid, andaria-describedbyrelationship, then clears the relationship as soon as the field becomes valid. - Public documentation canon now matches the current master brand and no longer links to repository-only ADR/GTM files from the generated site.
Added — audit remediation
lycato operator approvals/approve <digest>/deny <digest>— the create→approve→consume action-digest flow now has call sites. A scheduled agent that writes company truth with no branch and no diff (today:daily-digest) records a pending digest and does not run until one is approved. An unapproved slot is a failed run, so it stays eligible for retry.- Missed-minute catch-up in
lycato serve— a late tick replays every elapsed minute instead of dropping the slot.
Changed — audit remediation
pnpm docs:buildclears its output first, and the CI docs job runsscripts/ci/check-docs-public-tree.mjs, which fails the build if the tree about to be deployed holds any path outside the public allowlist. The currently-deployed site predates this and still serves the internal directories; removing them needs a deploy.lycato initcreatesmain, andlycato review approve's provenance gate resolves its base viaorigin/HEADand blocks when no base resolves, rather than passing the change through.- The notifier marks only channels that actually delivered. A failed webhook no longer banks the events into the once-per-day ledger, and the run reports failure.
- Operator access moved into
firestore.rules. The browser-sideisOperatorAdmin/elevateOperatorAdmin/assertTenantIsolationhelpers are deleted. - Nine unimported hosted modules moved to
packages/hosted/unshipped/— the plan-gate and billing subsystem, the provisioning saga, the company switcher, the mailbox mediator, the margin report. They are not shipped and not enforcing anything; seepackages/hosted/unshipped/README.md. (Superseded 2026-08-23: theapps/move, commit65ee343, relocatedpackages/hosted→apps/hostedand deleted theunshipped/tree and its README rather than carrying them across. Neither path resolves in the current checkout; the nine modules exist only in git history.) - Production CSP no longer whitelists
127.0.0.1, and/.well-known/{ucp,security.txt}are excluded from the SPA rewrite.
Added
- Diff risk scoring —
scoreRisknow scores deletions vs appends, annotates ledger net deltas and decision amendments, treatsdecisions/as high-risk, and setsrequiresExplicitReadfor high-risk diffs. Cockpit Review sorts by risk and withholds Approve until a high-risk diff is opened; CLIlycato reviewmatches. @lycato/agent-decision-draft—lycato operator decision-draft "…?"frames options/trade-offs intodecisions/{id}.mdasproposed. Frames; never decides.@lycato/agent-notifier+@lycato/corenotify — opt-in high-signal interrupts (obligation due, runway low, stale decision, stale review) via.founder/notify.yml. Delivers to.founder/notifications/and optional webhook. Wired intolycato sync/lycato serve(no-op when disabled).@lycato/agent-kpi-snapshot—lycato operator kpi-snapshotdraftskpis/{yyyy-mm-dd}.mdfrom the money ledger + run-ledger sync health.lycato doctor --jsonplus a Wiring report (configured adapters + telemetry posture).- Telemetry instrumentation —
recordRun/recordUsagewired into both run paths + an oclifpostrunhook;lycato initopt-in consent prompt. Still default-off, local-only. - Static doc-site —
pnpm docs:buildrenders the public subset ofdocs/to a self-contained HTML site (one dep,marked), plus a brand-true marketing home atdocs/site/home.html(site root). The subset is thePUBLIC_DOC_DIRSallowlist inscripts/build-docs.mjs; internal directories are not emitted. - Cockpit —
manualChunkscode-split + lazy money chart (~176→86KB gz first paint), global:focus-visiblering + CmdK dialog focus-trap, anErrorBoundary, a ⌘K search affordance, and a first-run onboarding card.
Changed
- Dependencies upgraded to latest across the workspace, including major
bumps: Tailwind 4 (CSS-first via
@tailwindcss/vite;postcss.config.js+tailwind.config.jsremoved, fonts moved to an@themeblock), Vite 8 (Rolldown), Vitest 4 (+ jsdom 26), TypeScript 6 (types: ["node"]intsconfig.base.json), Biome 2 (migratedbiome.json), Zod 4, octokit 5, recharts 3, lucide-react 1,@inquirer/prompts8,@fastify/cors11.engines.noderaised to>=22.13. Code migrations were small: Zod 4z.record(z.string(), …)+ZodType<T>, two lucide icon renames (CheckCircle2→CircleCheckBig,XCircle→CircleX), and a Vitest-4 class mock for octokit. All 316 tests + build + typecheck + Biome stay green. cockpit-devtools-smokemade Windows-portable (platform-aware Chrome path viaCHROME_PATH,pnpmspawned through a shell,localhostweb host, and a retrying Chrome-profile cleanup).- LF line endings enforced via
.gitattributes. plain/visible/stripe-atlasadapters now run underlycato sync.- Test suite 216 → 300+: a jsdom cockpit render harness (every page),
per-adapter pull tests, and core
money/pathscoverage.
Fixed
- Windows-only
pnpm build/pnpm typechecksilent no-op (POSIX-quoted workspace filter ran viacmd.exe). - Date-dependent run-ledger timestamp bug in
runSync(used wall clock instead of the injectednow).
[0.1.1] — 2026-05-21
Added
- Provider-agnostic LLM client.
@lycato/core/llmexportsLlmClient,createAnthropicClient,createOpenAIClient,createGeminiClient,createLlmClient,resolveLlmClient. Directfetch-based — no SDK dep. Default models pinned per provider (claude-opus-4-7,gpt-4o-mini,gemini-2.5-flash). --providerflag onlycato morning --auto-sync,lycato operator investor-update,lycato operator content-queue,lycato closeto override the auto-picked provider when multiple keys are set.requiredAnysemantics on sync steps — daily-digest now skips only when zero ofANTHROPIC_API_KEY/OPENAI_API_KEY/GEMINI_API_KEYare set.
Changed
- All four agents (
@lycato/agent-daily-digest,@lycato/agent-investor-update,@lycato/agent-content-queue,@lycato/agent-finance-close) now acceptLlmClientinstead ofPick<Anthropic, "messages">.
Removed
@anthropic-ai/sdkdep dropped from@lycato/cliand all four agent packages. Install footprint reduced.Run ledger.
@lycato/coreexportsappendRun,readRuns,withRunRecord. Every adapter/agent run writes a JSONL line to.founder/runs/YYYY-MM.jsonl(at,kind,name,ok,ms,error?,summary?). Wired intorunSync,morning --auto-sync,agent investor-update,agent content-queue,close.lycato logs. New CLIlycato logs [--limit N] [--kind adapter|agent] [--name X] [--since TS] [--json]tails the run ledger with status, duration, and summary/error.Cockpit Work page rewritten.
/api/runsnow reads the run ledger instead ofjournal/daily/. Surface shows kind, name, latency, summary, error per entry.
Changed (breaking — local cockpit only)
RunEntryAPI contract reshaped:{ at, kind, name, ok, ms, error?, summary? }. Old{ agent, date, file, preview }removed.
Added (Phase 3 — schema migrations)
- Migration engine.
@lycato/core/migrationsexportsMigrationtype,readRepoVersion,writeRepoVersion,runMigrations,CURRENT_REPO_VERSION,REGISTERED_MIGRATIONS. Forward-only, idempotent, with--dry-runand--to <ver>support. lycato migrate. New CLI command. Walks.co-md-version→CURRENT_REPO_VERSIONapplying each pending migration in order.- Baseline migrations.
0001_baseline_v0_1_0backfills missing.co-md-versionfor v0.0.x repos;0002_runs_gitignoreappends.founder/runs/to.gitignore(Phase 2 lock-in). lycato doctornow reports the repo schema version and recommendslycato migratewhen behind.lycato initwrites the current schema version fromCURRENT_REPO_VERSIONinstead of hardcoding0.1.0.- Kernel template
.gitignoreships with.founder/runs/for fresh repos so the migration is a no-op there.
Repository-only rationale: ADR-0015, ADR-0016, and ADR-0017 in
decisions/ADR_LOG.md.
Added (Phase 4 — cockpit cmd-K + global search)
/api/search?q=Fastify route reads the existingLycato/cache/index.json, classifies hits by path-prefix intoSearchHitKind, returns{ query, hits, indexBuiltAt, stale }. Lazy-builds the index on first call.POST /api/reindexrebuilds the on-disk index.- Cmd-K modal (
components/CmdK.tsx) — debounced search, arrow-key nav, enter-to-open, hit-kind chips, footer reindex prompt when index is stale (>24h). Shell.tsxlistens forcmd/ctrl+Kto toggle cmd-K. Hit activation routes to the most-relevant page.
Repository-only rationale: ADR-0018 in decisions/ADR_LOG.md.
Added (Phase 5 — WebSocket push)
/api/wsFastify route (@fastify/websocket) streams{ kind, path, at }events to all connected cockpits.- chokidar watcher monitors
WHEN.md,money/ledger/*.md,journal/daily/*.md,.founder/reviews/*.yml,.founder/runs/*.jsonl. Emits on add/change/unlink. useLive(kinds, handler)React hook with singleton WS + exponential reconnect backoff.useApiextended with arefreshfunction so any page can be wired to re-fetch on a live event.- Work page re-fetches on
runsevents; Review page re-fetches onreviewevents. - Feature flag
cockpit.live_updates: falsein.founder/config.ymldisables both watcher + WS route.
Repository-only rationale: ADR-0019 in decisions/ADR_LOG.md.
Added (Phase 6 — cockpit inline diff viewer)
/api/review/:branch/diffreturns{ branch, base, files: [{ file, status, before, after, isBinary, truncated }] }. Caps each file at 1MB; sniffs binary via NUL byte.DiffViewer.tsxrenders an in-browser LCS-based line diff per file with status chips (added/removed/modified) and truncated/binary indicators. No new client deps.- Review page branches now expand in place to show the diff on first click (lazy fetch).
Repository-only rationale: ADR-0020 in decisions/ADR_LOG.md.
Added (Phase 7 — cockpit inline edit + commit)
POST /api/fileaccepts{ path, branch, content, approver?, message? }. Writes the file on the target proposal branch and commits viasimple-git. Restores the founder's priorHEADin afinallyblock.policy.editableflag onPolicyRule. Default-editable paths:journal/daily/,content/queue/,investors/. HelpersisPathEditable(policy, path)andriskForPath(policy, path)exported from@lycato/core.- High-risk gate: writes to high-risk paths (e.g.
investors/) require a non-emptyapproverfield; surfaces as the commit author. - DiffViewer Edit mode: per-file Edit button swaps the after-pane to a textarea + approver input + Save & commit. Diff invalidates on success so the next render shows the new commit.
Repository-only rationale: ADR-0021 in decisions/ADR_LOG.md.
Added (Phase 8 — SDK + module system)
@lycato/[email protected]public package exposingAdapter,Agent,Moduleinterfaces +defineAdapter,defineAgent,defineModuleidentity helpers +LlmClientre-export from core. Surface pinned at 1.0.0.@lycato/core/modulesregistry:loadModules,addModule,removeModule,listModules,BUILT_IN_MODULES,findModule. Reads/writes.founder/modules.yml.- Built-in modules:
saas,services,d2c. Each declares directory layout + recommended adapters/agents. lycato module list / add / removeoclif topic commands.
Repository-only rationale: ADR-0022 in decisions/ADR_LOG.md.
Added (Phase 9 — self-hosted slice)
lycato servesingle-process supervisor — spawns cockpit + runsrunSyncon--interval(default 900s). Flags--skip-cockpit,--skip-sync. Replaces the need for an external cron in single-tenant installs.deploy/docker-compose.yml+deploy/Caddyfilereference stack with auto-TLS.docs/deployment/SELF_HOSTING.mdrunbook (install, upgrade, backup, hardening). Calls out KMS / Stripe / passkey / multi-tenant as deferred to hosted product launch.
Repository-only rationale: ADR-0023 in decisions/ADR_LOG.md.
Added (Phase 10 — capture endpoint + PWA shell)
POST /api/inboxaccepts{ title, body?, source? }and writesinbox/{yyyy-mm-dd}-{nanoid}.mdwith full frontmatter. Title required, body capped 64KB, source regex-validated.- PWA manifest at
public/manifest.webmanifest+ service worker atpublic/sw.js(network-first/api/*, cache-first/assets/*, HTML shell fallback). Registered fromindex.html. api.capture(...)frontend helper.
Repository-only rationale: ADR-0024 in decisions/ADR_LOG.md.
Deferred to v0.4.0+ (hosted product)
- KMS-backed encrypted secret store.
- Stripe checkout, per-tenant billing, passkey/SSO auth.
- Multi-tenant orchestration.
- Inbound email capture (Postmark webhook → inbox/).
- Voice capture via Whisper transcription.
- Managed daily backups to founder-owned S3.
Added (telemetry — local-side opt-in CLI)
@lycato/core/telemetryhelpers:readTelemetryConfig,writeTelemetryConfig,getInstallId(UUIDv4 vianode:crypto),rejectReason(deny-list against provider-key shapes + path separators + length > 32),recordEvent(appends to.founder/telemetry/YYYY-MM.jsonlonly when enabled; rejected events go torejected.jsonl),previewPayload(rolling-window aggregate in upstream shape),deleteTelemetryLocal.lycato telemetry status / on / off / preview / deleteoclif topic commands.- Default off. No upstream endpoint wired yet;
deleteis local-only. Perdocs/security/TELEMETRY_OPT_IN.md, call-site instrumentation + endpoint follow once justified.
[0.1.0] — 2026-05-19
First publishable alpha. Built end-to-end agent-drafts → founder-approves loop on a markdown+git substrate.
Added
- Memory primitive.
memory/{people,companies,projects,topics}/— file-per-entity addressable vialycato mem <key>,lycato mem ls,lycato mem find,lycato mem write. New cockpitMemorypage with tree + viewer. Core exports:readEntity,writeEntity,listEntities,findEntities,findOversizedEntities. Doctor warns on entities50KB.
- Provenance & evidence-rail. Convention: agent-authored lines
carry
<!-- src: <path> -->. Core exportswithProvenance,extractProvenance,checkProvenance.lycato audit --provenanceflags missing markers injournal/,investors/. Cockpit/api/filewith path-traversal guard. - Investor-update agent.
@lycato/agent-investor-update— deterministic financial summary + Claude-drafted Overview / Performance / Economics / Highlights / Lowlights / Asks. CLI:lycato operator investor-update. - Stripe adapter + reconcile.
@lycato/adapter-stripepulls balance transactions.@lycato/core/reconcilecross-matches Stripe charges with Mercury settlements.lycato reconcilewritesmoney/reconcile-YYYY-MM.md. - Content-queue agent.
@lycato/agent-content-queuedrafts 3-5 LinkedIn / X / blog candidates intocontent/queue/. - Importers.
lycato init --demoseeds a realistic company (5 people, 3 decisions, 60d ledger, 4 inbox items, 2 memory entries).lycato import notion <dir>,lycato import gmail-mbox <file>,lycato import linear <json-export>. - Risk-aware approvals.
.founder/policy.yml(with sensible defaults). Core:loadPolicy,scoreRisk.lycato reviewlists proposal branches with risk + reasons + auto-merge eligibility. Cockpit/api/reviewreturns risk per branch and approval status. Founder one-click approve via Cockpit button orlycato review approve <branch>— writes.founder/reviews/<branch>.yml. Merge stays manual. - BYO API key.
.founder/keys.env(gitignored, chmod 600). CLI:lycato keys,lycato keys set NAME VALUE.loadKeysIntoEnvwired intolycato sync,lycato doctor, agent runners. README "Your tokens. Your bill." positioning. - Derived index.
Lycato/cache/index.jsonrebuilt bylycato reindex. Core exportsbuildIndex,readIndex,searchIndex. - 3 new adapters: Plain, Visible, Stripe Atlas. Each follows the
client / transform / pull / indexlayout. - Cockpit shell + routing. Hash-based router, sidebar nav, six
pages (Today / Work / Memory / Company / Review / Settings). All
pages use
useApihook for typed data loading. Evidence rail on every panel. - CLI gaps filled.
lycato inbox,lycato inbox view,lycato inbox triage,lycato sync,lycato audit,lycato reconcile,lycato reindex,lycato mem*,lycato keys*,lycato operator investor-update,lycato operator content-queue,lycato import notion,lycato import gmail-mbox,lycato import linear,lycato review,lycato review approve. - CI matrix.
ubuntu / macos / windows× Node 22. - Docs site stub.
docs/site/index.mdwith command table + architecture + trust boundaries. - Demo script.
docs/demo/script.md(5 min on-camera path).
Changed
- All 15 workspace packages bumped from
0.0.0to0.1.0.lycato initwrites.co-md-version: 0.1.0. - Cockpit API extracted from single
server.tsinto per-route files underapi/. Typed response shapes incontracts.ts. Structured error envelope{ error: { code, message, path? } }withApiError. - CORS locked to
http://localhost:5173by default; override viaLYCATO_CORS_ORIGIN. lycato auditwalkspeople/,decisions/,journal/daily/for schema validation; new--provenanceflag adds journal/investor marker checks.- Numeric formatting in money commands forced to
en-USso output is locale-independent.
Fixed
- Pre-existing Windows-path fragility in
core/test/search.test.ts(normalisepath.sep→/). - Pre-existing locale-dependent number formatting in
cap-table.ts,money/runway.ts,money/summary.ts.
Security
.founder/keys.envis gitignored and written with0o600.- Cockpit
/api/filerejects path traversal and absolute paths. - Approval records are local files; the cockpit never merges branches.
Notes
- 154/154 tests pass (46 files) on the local matrix. CI matrix configured for ubuntu/macos/windows; first run pending push.
npm publishnot run by the agent. Manual: see Phase 10 deliverable indocs/superpowers/plans/2026-05-19-co-md-research-driven-10-phase.md.
[0.0.4] — 2026-05-10
Web cockpit v1: React 19 + Recharts dashboard. Local Fastify API.
lycato cockpit launches the dashboard.
[0.0.3] — 2026-05-08
lycato people, lycato decide, lycato equity, lycato money subcommands.
[0.0.2] — 2026-05-08
lycato doctor, lycato search, lycato obligations, lycato close; GitHub adapter
and finance-close agent.
[0.0.1] — 2026-05-05
Backbone: kernel template + lycato init + Mercury adapter + daily-digest
agent.