2026-10-11 17:09 UTC

Singularity's maintainers claim their released session-learning memory hook โ€” which stores workflows from finished coding-agent runs and replays them via plain-text matching โ€” cuts repeat-task token costs by up to 78% (1.9Mโ†’423k tokens on Excalidraw) across Claude Code, Codex, Gemini CLI, and other harnesses.

state: watchingheat: highuncertainty: mediumconvergesscott: mediumagent-memory coding-agents token-optimization procedural-memorypandacoverluvmakin

What is this?

The web search returned no results for this Show HN release. The only material is the case hypothesis itself: a first-party claim by maintainers 'pandacover' and 'luvmakin' that their 'Singularity' session-learning memory hook โ€” storing workflows from finished coding-agent runs and replaying them via plain-text matching โ€” reduces repeat-task token costs by up to 78% (1.9Mโ†’423k tokens on Excalidraw) across Claude Code, Codex, Gemini CLI, and other harnesses. No independent verification, third-party coverage, or repository links are available in the supplied snippets.

Why it matters to Scott

Singularity's session-learning memory hook โ€” storing workflows from finished coding-agent runs and replaying them via plain-text matching across Claude Code, Codex, and Gemini CLI โ€” independently implements the durable external state / procedural memory pattern Scott's frameworks (long-running-agents, context-engineering, recognition-loop, checkpoint-discipline, knowledge-fossils, working-fidelity) argue for. The quantified 78% token reduction (1.9Mโ†’423k on Excalidraw) adds a concrete data point to the token-optimization territory Scott tracks (token-discipline, attention-budget, signal-density, prefix-caching-economics), alongside radar episodes like Shunt (82โ€“94%), Tura (~80%), and AgentJIT. The multi-harness hook directly bears on his harness-interoperability work (dev-wiki, ask, search-conversations, deterministic-agent-control-plane) and the radar's cross-harness memory episodes (Txcript, Teleport, HolaOS, MemTether). Not high because it's one of many similar implementations; would be higher if it challenged a specific claim or opened a publishing angle.
ip:framework.long-running-agentsip:concept.durable-external-stateip:concept.agent-mortalityip:concept.session-isolationip:concept.checkpoint-disciplineip:concept.knowledge-fossilsip:concept.working-fidelityip:framework.recognition-loopip:concept.agent-authored-context-compactionip:concept.resumable-agent-job-control-planeip:framework.context-engineeringip:concept.token-disciplineip:concept.attention-budgetip:concept.signal-densityip:dev:technology.claude-codeip:dev:technology.codex-cliip:dev:technology.geminiip:dev:project.dev-wikiip:dev:project.askip:dev:project.search-conversationsradar:concept.agent-memoryradar:concept.coding-agentsradar:concept.token-efficiencyradar:concept.agent-harnessesradar:concept.agent-interoperabilityradar:toucan-transcript-session-memoryradar:skillmem-provenance-gated-procedural-memoryradar:shunt-claude-code-token-savingsradar:tura-token-efficient-agentradar:backpass-evidence-gated-memory-editsradar:agentjit-trajectory-compilationradar:compiled-agent-skills-token-reductionradar:txcript-cross-harness-session-conversionradar:teleport-cross-harness-session-portabilityradar:holaos-shared-agent-workspaceradar:memtether-symlink-shared-agent-memoryradar:continuity-claude-code-decision-memoryradar:nexusmem-coding-agent-memoryradar:docs-first-agent-continuity-protocol
queries asked of Scott's wikis
  • agent-memory procedural-memory coding-agents
  • token-optimization repeat-task caching coding-agents
  • local-inference economics agent-harnesses
  • session-learning memory-hooks plain-text-matching
  • coding-agent harnesses Claude-Code Codex Gemini-CLI interop
  • open-source agent-memory frameworks reusable-artifacts

Measured heat

now 0 pts/hpeak 3 pts/hcomments 0/hpeers p14momentum: steady2 platformsage 266h
points/hour across evidence ยท reading as of 2026-10-12 02:59:37.977291+11:00 ยท deterministic, not a model opinion

How the heat travelled

09-30 14:00โญ origin echo-reconstructedThe repo README is the primary artifact: "Procedural memory for coding agents: learn from past Claude Code sessions so repeated and similar
Luv ("luv makin", GitHub: pandacover, software engineer at Tekion, Bangalore) on github (echo) ยท attributed from hn.story.50004683
โ€”
10-08 11:47first on hacker news ยท published ยท +189.8hShow HN: Singularity โ€“ memory that makes coding agents cheaper on repeat work
luvmakin
โ€”
10-08 11:47amplified on hacker news ๐Ÿ‘‘hn.story.50004683
luvmakin
peak 2 ยท 0 comments ยท 98% of case engagement
10-08 12:32our radar first saw it ยท +190.5hdiscovery anchor: hn.story.50004683โ€”
10-08 13:18reached heat=high ยท +191.3h ยท via queue+ledgerโ€”โ€”

Evidence (2) โ€” โญ canonical anchor

sourceobjectauthorscorecomments
๐ŸŸง hnShow HN: Singularity โ€“ memory that makes coding agents cheaper on repeat work
Retrieved article excerpt

Open article ยท Retrieved 2026-10-08T12:42:04.993045+00:00

# singularity

Procedural memory for coding agents: learn from past Claude Code sessions so
repeated and similar tasks take less time and fewer tokens. See `HANDOFF.md`
for the design, decisions and results, and `CLAUDE.md` for how the code is
written.

## Install

One command. It checks your machine, puts singularity in `~/.singularity`,
and walks you through setting memory up in the coding agents it finds.

macOS, Linux, WSL or Git Bash:

```
curl -fsSL --connect-timeout 10 https://raw.githubusercontent.com/pandacover/singularity/main/install.sh | sh
```

Windows PowerShell:

```
irm https://raw.githubusercontent.com/pandacover/singularity/main/install.ps1 | iex
```

You need git. Without Node.js 24 or later on your PATH, the installer
fetches its own copy into `~/.singularity/node` (checked against nodejs.org's
checksums) and changes nothing else. Memory learns from Claude Code sessions,
and with Claude Code's model calls, so have Claude Code too. WSL keeps its own
agents: for agents you run on Windows, run the PowerShell command on Windows.
(`--connect-timeout` makes curl move on quickly from a GitHub address your
network can't reach, instead of waiting minutes.)

| Agent | What memory does there | What setup adds |
| --- | --- | --- |
| Claude Code | hands over at task start, warns during the task, learns from sessions | hooks in `~/.claude/settings.json`, skill |
| Codex | hands over at task start, warns during the task (trust the hooks once with `/hooks`) | hooks in `~/.codex/hooks.json`, skill |
| Gemini CLI | hands over at task start, warns during the task | hooks in `~/.gemini/settings.json`, skill |
| Droid | hands over at task start, warns during the task | hooks in `~/.factory/hooks.json`, skill |
| Cursor, OpenCode, other agents that read `~/.agents/skills` | when you ask for it | skill |

Setup also puts the `singularity` command on your PATH and asks whether
memory may learn on its own (about $0.25 a round on your Claude account, at
most $1 a day). It never touches the rest of an agent's settings, and keeps a
copy of each file it changes (`<file>.before-singularity`).

How memory gets to know a repo: a Claude Code session that ends with its
change committed and its tests passing becomes a record. After a few records
in a repo, memory learns workflows from them (where each kind of change goes,
how it is checked, the mistakes made on the way). From then on, a task that
needs them gets them with its first prompt, found in the code as it is that
day. In a repo with earlier Claude Code sessions, setup offers to start from
those.

```
singularity status              # which agents have memory, and what it knows per repo
singularity recall "<task>"     # what a task here would be handed (no model call)
singularity learn [--past]      # learn now; --past starts from this repo's earlier sessions
singularity setup               # again, to update or change your answers
singularity uninstall [--purge] # take memory out of every agent (memory stays unless --purge)
```

From a clone instead: `npm install`, then `node apps/cli/src/cli.ts setup`.

## Develop

A Turborepo monorepo with npm workspaces:

| Workspace | What it is |
| --- | --- |
| `apps/cli` | the command line, hooks, memory and eval harness: TypeScript 7 and Effect 4, run directly by Node 24 (no build step) |
| `apps/landing` | the landing page: Vite and React |

```
npm install
npm test               # every workspace's tests (vitest), through turbo
npm run typecheck      # every workspace's tsc
npm run build          # the landing page, into apps/landing/dist
npm run dev            # the landing page's dev server
npm run cli -- <args>  # the command line, same as node apps/cli/src/cli.ts <args>
```

Commands in this README run from the repo root, where eval runs go
(`runs/`).

## Summarize a session

```
node apps/cli/src/cli.ts traces <session id or path to .jsonl> [--json]
```

Reads Claude Code's transcript (including subagents) and prints tokens, tool
calls, failed calls, and repeated file reads.

## Local memory

Memory lives in `~/.singularity` (or `$SINGULARITY_HOME`). It belongs to one
tenant, named in its `config.json`, and is about subjects: repos, recognized
by their root commits and remotes, so every clone of a repo is the same
subject.

**Workflow records**, one per finished run, are the evidence:

```
node apps/cli/src/cli.ts record import runs/excalidraw/*/ [--task ID ...]   # eval runs (of some tasks only)
node apps/cli/src/cli.ts record session SESSION_ID              # a session that committed its change with passing tests
node apps/cli/src/cli.ts record annotate --all --per-task 4     # a model's reading, a few cents a record
node apps/cli/src/cli.ts record list | show ID
```

A record holds what the log and the diff show without any model: files
changed, where in them the run added its lines (the existing lines just above
and below, never the new ones), every shell command and whether it worked,
and detours (a call that failed, the later call that fixed it, and the tokens
in between). The model's
reading adds the task's kind, its steps (each asked for, needed, or the
agent's own choice), landmarks in the code, and what each detour teaches, with
an exact trigger. Every claim is checked against the code at the run's commit
and against the log, and dropped if it doesn't hold.

**The memory graph** is built from the records: task kinds with their routes
(required and optional steps, with the condition for each optional one),
steps with where they happen in each repo, and warnings with their triggers.

```
node apps/cli/src/cli.ts memory build --conditions   # merge the records; a replay check commits or rejects
node apps/cli/src/cli.ts memory show [VERSION]
node apps/cli/src/cli.ts memory replay | triggers | candidates
```

Each build is a candidate. The replay check asks, for every past task,
whether the graph would hand it what it needed and nothing else, and whether
its triggers fire on commands that worked; a build that hands a task a step
it never asked for is rejected. `memory triggers` replays recorded runs
through the warnings' triggers, to see which would have arrived before their
mistake. `--conditions` has a model write the conditions of optional steps
and decide which near-identical step names are one step (a few cents).

**Search**, exact and by words (search by meaning is for the hosted version):

```
node apps/cli/src/cli.ts search help dialog shortcut
node apps/cli/src/cli.ts search --exact handleKeyboardGlobally [--type record|kind|step|warning]
```

**Hand-over**, through Claude Code hooks:

```
node apps/cli/src/cli.ts handover --cwd REPO "Change the zen mode shortcut to Alt+M"   # what a task would get
node apps/cli/src/cli.ts hooks install [--scope user|project|local]                   # or `hooks print`, for claude --settings
node apps/cli/src/cli.ts hooks status | uninstall
```

At a session's first prompt, the hook hands over the route for the task and
the warnings on its steps: word search proposes up to three task kinds, and a
model confirms one and picks its steps (about $0.03 and a few seconds). With
the route comes the code at its places: the hook looks up, in the working
tree, the lines that earlier runs of the kind made each step's edits next to,
and hands over what is around them now, so the agent can edit without reading
for the places first. Memory holds which lines to look for, not the code. It
all stays under 10,000 characters, where Claude Code cuts a hook's text. After
each shell command or edit, a warning whose exact trigger appears is handed
over, once a session. When a session ends with a committed change and passing
tests, it becomes a record. `SINGULARITY_HOOKS=off` turns the hooks off; the
eval harness sets it, so installed hooks stay out of measurement runs.

That memory is v0 (tag `memory-v0`); `hooks install` installs its hooks.
Memory v1 is what `singularity setup` installs for daily use (above), and
lives in the same home, under `tenants/<tenant>/workflows/`. Setup replaces
v0's hooks if it finds them. In daily use v1 learns repo by repo
(`apps/cli/src/workflows/Learn.ts`): a repo's memory is learned alone and merged back,
so one repo never replaces another's, and ids two repos share get the second
repo's id appended. The commands below are the parts it is made of, as the
eval suites use them:

```
node apps/cli/src/cli.ts workflows build [--task ID ...] [--repo DIR] [--fresh]       # induce from the records (one model call or two)
node apps/cli/src/cli.ts workflows show [AT] [--json]                                 # print it
node apps/cli/src/cli.ts workflows cues [--repo DIR]                                   # write cues, so tasks are picked without a model (one model call or two)
node apps/cli/src/cli.ts workflows finish [--repo DIR]                                 # learn what each workflow's checks rewrite (no model)
node apps/cli/src/cli.ts workflows handover TASK... --cwd REPO [--at COMMIT] [--pick cues|words|model] [--parts 2] [--draft] # preview a task's hand-over
node apps/cli/src/cli.ts workflows evolve [--task ID ...] [--setup S ...] [--records-from HOME] [--repo DIR] [--dry-run] # learn from new runs
node apps/cli/src/cli.ts workflows common --task ID --task ID ... [--kind WORDS] [--repo DIR] [--dry-run] # learn what runs of different tasks of a kind did alike
node apps/cli/src/cli.ts workflows candidates                                         # proposals and what became of them
```

Since the tenth session: **what tasks of a kind share** (`workflows common`,
`apps/cli/src/workflows/Common.ts`). Learned task by task, two bug fixes became a
workflow each, which no other bug can use. This pass reads the runs of
several tasks of one kind (bug fixes) and keeps only what runs of at least two
different tasks did: how a bug is reproduced in a test here, how the fix is
checked (the test failing without it, with `git stash`), the mistakes made on
the way. Its places include blocks runs **read** without changing them
(`apps/cli/src/workflows/Reads.ts`), such as the test helpers' `Keyboard` class, which
the hand-over shows as an outline: the block's first line and its members',
from the code at task start. Run `workflows cues` after it.

Since the eighth session: the hand-over ends with **one command** that runs
every check its workflows need, with the snapshot files earlier runs
regenerated (`apps/cli/src/workflows/Finish.ts`); `evolve` also reads **what each run
still looked up before its first edit** (`apps/cli/src/workflows/Lookups.ts`;
`--dry-run` prints it), writes the cues again and replays with them; and the
`workflows-split` setup carries a hand-over longer than one hook can (Claude
Code cuts each at 10,000 characters) in two parts, from two task-start hooks.

v1 keeps small workflows written with blanks (`{field}`, `{key}`), learned
from runs, and a graph of them whose edges say when one leads to another. A
step's place is kept as the blocks that enclose the edit (`class App โ€บ getContextMenuItems โ€บ if (this.state.viewModeEnabled) โ€บ return [`), never as
code; at task start its hooks (`apps/cli/src/workflows/hook.ts`) pick the workflows the
task needs, find each place in the code as it is (in the file it moved to, if
it moved) and hand them over with current line numbers. `evolve` revises
memory from what new runs did and what it showed them, and keeps the revision
only if, replayed over the runs, it shows more of the places they edited and
fewer they left alone.

**Local first** (tag `memory-local-first`): picking makes no model call. Each
workflow carries cues, phrases that say a task needs it and where a task
states its blanks' values, written once by `workflows cues`
(`apps/cli/src/workflows/CueWriter.ts`); at task start they are matched exactly against
the task, its negated clauses ("don't add a shortcut") left out, and the
blanks the task states are filled in (`apps/cli/src/workflows/Cues.ts`). That is the
hook's default
luvmakin40
๐ŸŸง echo.github โญThe repo README is the primary artifact: "Procedural memory for coding agents: learn from past Claude Code sessions so repeated and similar Luv ("luv makin", GitHub: pandacover, software engineer at Tekion, Bangalore)โ€”โ€”

Interpretation history

Decision trace