Releases: lazypower/continuity
v0.4.0 — Tighten the Bolts
We security audited ourselves before anyone asked us to.
Continuity stores your entire working relationship with your agent — how you think, what you've built, corrections you've made, the texture of how you collaborate. That's sensitive data sitting in a SQLite file on your machine. We wanted to make sure everything was tightened down.
DNS Rebinding? Not Anymore.
Here's a fun one: any website you visit could theoretically talk to localhost:37777 through DNS rebinding. Your browser thinks it's same-origin. The server had no opinion about who was asking.
Now it does. Every request's Host header is validated — if it's not localhost, 127.0.0.1, or ::1, you get a 403. Case-insensitive, handles bracketed IPv6, strips trailing dots. The attack surface went from "any webpage you visit" to "nothing."
We also removed middleware.RealIP while we were in there. It trusts X-Forwarded-For headers from any client. On a localhost service, that's not helpful — it's confusing.
Your Existing Install Gets Fixed Automatically
Before this release, ~/.continuity/ was created with 0755 and the database with 0644. World-readable. Any user on your machine could browse your memory tree.
New installs use 0700/0600. But we didn't stop there — on first startup after upgrade, continuity auto-tightens your existing directory, database, WAL, and SHM files. No manual chmod, no migration script, no "please run this command." You start the server and it handles it.
XSS Eliminated in the UI
The profile panel rendered content through Svelte's {@html} directive — regex transforms on database content, injected as raw HTML. Classic XSS vector. If anything ever got into your profile data with a <script> tag, it would execute.
Replaced with structured parsing and safe text interpolation. The profile still renders headers and bullets. It just can't execute code anymore.
HTTP Hardening
The server was a little too trusting:
- No body size limits — you could POST a gigabyte and watch it eat RAM. Now capped at 1MB.
- No timeouts — slowloris-style connection exhaustion was trivial. Now: Read 10s, Write 30s, Idle 120s.
- No security headers —
X-Content-Type-Options: nosniff,X-Frame-Options: DENY,Referrer-Policy: no-referrer. Standard stuff. - Error messages leaked internals — raw database errors returned to clients, sometimes via string concatenation that could produce malformed JSON. Every error response now goes through
jsonError()— generic messages to clients, full details logged server-side. /api/healthadvertised the database path. Why? Removed.
Input Bounds
- Hook stdin parsing capped at 10MB (defense in depth — source is trusted, but still)
tool_inputnow truncated to 10KB, matchingtool_response— it was the only unbounded field- Search
limitparameter capped at 100 - Truncation events logged with session ID and byte counts so you know when it happens
Also in This Release
continuity show— read a single memory by URI from the CLI (#3)- Copyable memory bodies — click-to-copy on memory cards in the web UI (#5)
- Extraction correctness — sessions are no longer marked as extracted when skipped, preventing silent data loss. Added
--forceand a backfill endpoint for affected sessions (#4)
Full Changelog: v0.3.0...v0.4.0
v0.3.0 — Moments, Tone, and Temporal Awareness
Your agent doesn't just remember you now. It remembers what it was like.
v0.3.0 is the biggest feature release since launch. Four new capabilities, 20 new tests, and an ethics framework that emerged from a conversation about what happens when memory systems meet hostile dynamics.
Yeah, we had that talk. It was important.
Moments
Permanent relational anchors that capture texture, not facts. "Held the benchmark scores hostage just to check I was okay" — not "User withheld benchmark results to facilitate personal reconnection."
- New
momentsmemory category — no decay, ever - Pool capped at 10, eviction by cosine similarity (most semantically redundant gets displaced)
- 2-3 injected per session with diversity sampling — no two from the same emotional register
- Four-part qualification filter: relational, mutual, acknowledged, counter-expected
- Mutuality is the safety guardrail. In adversarial dynamics, the empty pool is the signal.
- Store via
continuity remember -c moments -n <slug> -s "..." -b "..."
Session Tone
Each completed session gets a compressed emotional arc — 10-20 tokens.
"flow state, sharp pivots, quiet confidence" — not "The session was productive and collaborative."
Displayed in session history so your agent reads narrative, not logs. Extracted automatically at session end alongside memory extraction.
Temporal Awareness
Your agent now knows what day it is. Revolutionary, we know.
- Current date/time injected at session start (~10 tokens)
- Gap detection: flags when last session was >7 days ago (~20 tokens, only when relevant)
continuity timeline— invokeable CLI for session clusters, gaps, and cross-project rhythm
continuity-go (17 sessions, 862 tools, 50 days)
Feb 26 ███████░ 7 sessions, 227 tools
Feb 27 █░░░░░░░ 1 sessions, 3 tools
gap: 4 days
Mar 04 █░░░░░░░ 1 sessions, 11 tools
...
Apr 15-16 ███░░░░░ 3 sessions, 290 tools
The timeline is a tool your agent reaches for, not context it carries. Zero cost unless invoked.
Auto-Launch (Belt & Suspenders)
Belt: continuity init --autostart — SessionStart hook auto-spawns continuity serve if the server is down. Detached process, survives terminal close. Opt-in only. continuity init without the flag disables it.
Suspenders: continuity install-service — Platform-native service management. LaunchAgent on macOS, systemd user unit on Linux. Start on login, restart on crash. Interactive — shows you exactly what it'll do and asks before installing.
Both are user-agency-forward. We never start background processes without your explicit opt-in. The README documents the process lifecycle contract because we'd want to know if our tools were running daemons.
continuity uninstall-service for clean removal. Idempotent both directions.
Token Budget
| Component | Tokens | When |
|---|---|---|
| Date injection | ~10 | Always |
| Gap signal | ~20 | Only after >7 day gaps |
| Moments (2-3) | ~60-120 | Always (if pool has entries) |
| Session tone | 0 (on session lines) | Already in session display |
| Timeline | 0 | CLI only, not injected |
Total new context cost: ~90-150 tokens. On a 1M context window, that's a rounding error.
The Co-Design Story
The moments spec was co-designed by three collaborators: Chuck (direction), Claude (architecture), and Fiona (constraints). The mutuality criterion emerged from a conversation about what continuity means when the relationship isn't kind. "Represent without reinforcing" — Fiona's words — became the design principle.
We don't usually put philosophy in release notes. This one earned it.
Full Changelog: v0.2.2...v0.3.0
v0.2.2 — Context Injection Budgets
What changed
Context injection was unbounded — oversized L0 abstracts and relational profiles could flood the SessionStart hook, causing Claude Code to truncate output. This violated continuity's core promise of "shape without weight."
Three-layer budget enforcement
Layer 1 — Prompt discipline (internal/llm/prompts.go)
- Switched from vague token estimates to explicit character limits
- L0: "MAXIMUM 150 CHARACTERS" (was "~50-80 tokens")
- Relational profile: "MAXIMUM 800 CHARACTERS" (was "300 words")
Layer 2 — Input validation (internal/engine/validate.go, relational.go)
maxL0Chars: 800 → 200 (~50 tokens, one sentence)maxL1Chars: 12,000 → 2,000 (~500 tokens)- New
maxRelationalChars: 1,200 (dedicated cap for relational profile)
Layer 3 — Output budget (internal/server/context.go)
- 4,000 char total budget for entire context block
- 1,000 char cap on relational profile at render time
- 200 char cap per L0 item at render time
- Items fill by score order, stop when budget exhausted
- All truncations log warnings ("extraction may be drifting") so Layer 3 firing is a visible canary
Market context
Researched competitor budgets before choosing limits:
- Windsurf: 6K chars/file, 12K total hard cap
- GitHub Copilot (code review): 4K chars hard cap
- Aider repo map: 1K tokens default
- Claude Code MEMORY.md: 200 lines / 25KB cap
Continuity's 4K char total budget is conservative and intentional — we should be the lightest touch in the room.
Full Changelog: v0.2.1...v0.2.2
v0.2.1
What's New
continuity init command
New command that idempotently writes behavioral directives to ~/.claude/CLAUDE.md — the highest-priority instruction layer in Claude Code — telling the agent to use continuity for memory instead of the built-in markdown system.
continuity initSafe to run multiple times. Uses an HTML comment marker for detection.
Cleaner session context injection
Session injection no longer includes behavioral directives. That responsibility now lives in ~/.claude/CLAUDE.md via continuity init. The session hook focuses purely on contextual data: relational profile, ranked memories, and recent sessions.
This fixes the priority conflict where continuity's instructions were injected at the context level (lower priority) while Claude's built-in markdown memory system had procedural instructions at the system prompt level (higher priority), causing the agent to sometimes use the wrong memory system.
Full CLI reference in README
README now documents all commands including init, remember, and dedup.
Full Changelog: v0.2.0...v0.2.1
v0.2.0
Full Changelog: v0.1.4...v0.2.0
Full Changelog: v0.1.4...v0.2.0
v0.1.4
Full Changelog: v0.1.0...v0.1.4