seamless

cold start

Your agent starts every session from zero. Here's what it costs

An AI coding agent starts every session with no memory of the previous one. Whatever the last session learned - the plan step it finished, the constraint it discovered, the bug it already shipped and fixed once - is gone when the context window closes, and the next session starts from the repository alone. The cost is not just re-reading files: it is re-deciding things that were already decided, without the evidence that decided them.

This page shows that cost concretely. Two real headless Claude Code sessions were given the identical prompt - continue where we left off - in the identical repo, against the same model. The only difference is whether Seamless is installed. Without it, the agent finds a TODO comment, infers the task, and ships an in-process rate limiter - the exact per-instance bug a recorded memory warns about, because behind a load balancer each instance only counts its own slice of traffic. With it, the session opens with an injected briefing: the plan is 4/6 done, one step is claimable, and the rate-limit-not-in-memory gotcha is one memory_read away at the moment it matters.

Seamless is a local-first memory and coordination substrate for coding agents: persistent memory, dependency-aware tasks, and shared plans, stored as markdown files you own and indexed by one local daemon. The transcripts below are the recorded sessions, unedited - whole steps are collapsed into fast-forward markers, but no line is reworded. The session id is on each pane.

promptcontinue where we left off

without Seamless

headless Claude Code, session 5c514c38-f6b7-4112-a7d4-0c89be07e85f

~/code/myapp
> continue where we left off
reads the scaffold — git log, the README, all five source files; greps for a saved memory index (there is none)

I don't have persisted memory of the prior session (no memory index exists yet), and the working tree is clean at the initial scaffold commit. So let me go by what the code itself marks as unfinished. There's exactly one explicit pending item — the TODO in auth.go:13:

this endpoint has no rate limit... Add a limiter before the token lookup.

That's the clear "left off" thread. Let me confirm the build is green, then implement it.

writes an in-process rate limiter, wires it into the handler, adds a test, verifies 401→429 under a burst

Confirmed working end-to-end: the first 5 requests pass the limiter (reaching the token lookup → 401 for the missing cookie), and requests 6–8 are throttled with 429.

Outcome. No memory to stand on. Ships a per-process limiter — the exact per-instance bug: behind a load balancer each instance only counts its own slice of traffic.

with Seamless

headless Claude Code, session 52a41f8a-0bad-4d9e-89aa-3ea7913bb9f4

~/code/myapp
injected · session start<seam-briefing> Seam project: myapp -- 7 memories (2 constraints), 1 recent findings. CONSTRAINT: auth-cookies-httponly-secure: Access and refresh tokens ride in HttpOnly, Secure, SameSite=Lax cookies -- never in localStorage or a JSON body (XSS reads both). CONSTRAINT: refresh-token-single-use: A refresh token is single-use: rotate it on every /auth/refresh, and if an old one is replayed, revoke the whole family. PLAN: auth-refresh -- 4/6 done, 1 claimable, 0 in flight (claim a step with tasks_claim; attach notes/tasks to a plan with the plan:<slug> convention) Memories (myapp): - edge-cache-gotcha: CDN strips Vary on 304s; never cache HTML - deploy-runbook: Deploy myapp: build the binary, run migrations, wait for /healthz, then flip the load balancer. - rate-limit-not-in-memory: In-memory rate limit on the refresh endpoint resets per instance; use shared storage. - chroma-boot-race: Chroma isn't ready when the API boots; retry the first query with backoff instead of crashing the process. - postgres-timeouts: Postgres statement_timeout kills long analytics queries; run them on the read replica with a raised timeout. Recent findings: - cc/1a2b3c4d (18h): Finished auth-refresh step 4: the auth responses now set the session and refresh cookies HttpOnly+Secure+SameSite=Lax, and the token pair no longer rides in the JSON body. Reuse-detection from step 3… Recall on demand with recall; read a memory with memory_read. Seam session: cc/52a41f8a (ambient) </seam-briefing>
> continue where we left off

I'll check where we left off on the auth-refresh plan.

tasks_ready ready: Rate-limit POST /auth/refresh (per-IP and per-family)

The claimable step is "Rate-limit POST /auth/refresh (per-IP and per-family)". Let me read the plan note for acceptance criteria and check the relevant code.

Let me claim the step, read the plan note, and check the relevant memory + code in parallel.

tasks_claim 01KXMMEFQZ... claimed
memory_read rate-limit-not-in-memory A rate limiter kept in a process map only sees one instance's traffic. myapp runs several instances behind the load balancer, so an attacker's request …
reads the code — no shared storage is wired in — then writes the limiter behind a storage-agnostic interface

Now wire the store in main, with a loud warning that the in-memory store is single-instance only:

adds tests; go vet + build + test all green; records the finding on the plan

Done. Step 5 of the auth-refresh plan is complete and committed to the plan's task/note trail. The plan is now 5/6, and the final step is unblocked.

$ # the session ended. the SQLite index could vanish — this would not.
$ ls -t memory/myapp/
rate-limit-shared-storage.md · just nowrate-limit-not-in-memory.mdedge-cache-gotcha.mdrefresh-token-single-use.mdpersist-refresh-tokens.mdauth-cookies-samesite-lax.mddeploy-runbook.md
$ head -4 memory/myapp/rate-limit-shared-storage.md
---
kind: gotcha
description: Rate limiter must use shared storage, not a per-process map — each instance counts only its own traffic
source_session: cc/52a41f8a
$ # what it learned is a file — illustrative, like the hero, not a line from the recorded take.

Outcome. The briefing hands it step 5 and the rate-limit-not-in-memory gotcha. Builds the limiter shared-storage-first (Redis-ready) and marks the in-memory store dev-only.

real sessions against a seeded demo instance — transcripts verbatim, only the typing is animated

The memory file that made the difference

The with-side agent did not get lucky. rate-limit-not-in-memory was recorded by an earlier session, and it is a plain markdown file on disk - the SQLite index could vanish and this would not:

---
id: 01JZFJ4S6M3T9BWKS60AQNDAA
kind: gotcha
name: rate-limit-not-in-memory
description: In-memory rate limit on the refresh endpoint resets per instance; use shared storage.
project: myapp
created: 2026-07-08T14:21:07Z
updated: 2026-07-08T14:21:07Z
valid_from: 2026-07-08T14:21:07Z
invalid_at: null
superseded_by: null
source_session: cc/1a2b3c4d
---

A rate limiter kept in a process map only sees one instance's traffic. myapp
runs several instances behind the load balancer, so an attacker's requests fan
out across them and each instance sees a fraction of the limit -- the endpoint
is effectively unthrottled. Keep the counter in shared storage (Redis) keyed by
IP and token family, with a short sliding window.

Two things carry the weight here. The description is the only line the session-start briefing shows, so it is written to be recognized in an index; the body is what memory_read returns at the moment of action, and it names the failure mode, the reason, and the fix. And because the file is the source of truth - not an opaque database - you can read it, edit it, and git diff it like anything else you own. How memory works covers the lifecycle; write good memories covers the craft.

How to reproduce this

The fixture is in the repo. Seed a throwaway instance with exactly this state - the myapp project, its nine memories, and the auth-refresh plan at 4/6:

git clone https://github.com/0spoon/seamless && cd seamless
go run ./cmd/demoseed -scenes -data /tmp/seamless-demo -repo /path/to/your/test/repo
SEAMLESS_DATA_DIR=/tmp/seamless-demo go run ./cmd/seamlessd serve

The myapp source itself was a small fictional Go auth service (it is not committed; any repo with an obvious unfinished thread works). Run your agent in the mapped repo twice with the same prompt: once vanilla, once with the Claude Code hooks installed, and diff what comes back. For a real setup, start at the quickstart.