Skip to main content
Glama
Dharundp6

carryforward

by Dharundp6

carryforward

What your last session knew, scored against what this one is doing.

An MCP server with two tools. record saves a fact the moment it happens. recall brings those facts back when you start a task, and uses Jev to keep only the ones that matter right now.

Nothing is summarised. Nothing is deleted.

npm CI MIT powered by Jev

carryforward recall in a terminal, showing a rule kept in full, a decision scored 0.91 for the task, a measurement shown as one line, and six entries omitted

Contents

Related MCP server: engram

The problem

Your session ends, or it gets compacted halfway through. The next one starts from a summary, and summaries lose things:

  • The reason behind a decision is gone, so you argue about it again.

  • A number you measured is gone, so you measure it again or guess.

  • A rule you set is gone, so it gets broken.

  • A guess from last week is now repeated as a fact.

Every agent you spawn has the same problem, many times a day.

What it looks like

You save facts as you go:

record  constraint  "never force-push, a guard that stops you is telling you something"
record  decision    "the hook warns instead of blocking, since blocking forces --no-verify"  ref: .git/hooks/pre-push
record  measurement "14 decisions cost $0.00059, 318 ms each"  ref: triage.mjs  refresh: not reproducible
record  thread      "email sign-in branch is parked until the dashboard work restarts"  ref: branch dharun-dev/email-signin

Next session, you start a task:

recall  "add the scope check as a CI job"

And you get back only what that task needs:

# Carried forward
_task: add the scope check as a CI job_

## Always
- [constraint] never force-push, a guard that stops you is telling you something

## Live for this task
- [decision · p=0.91] the hook warns instead of blocking, since blocking forces --no-verify
  ref: .git/hooks/pre-push

## Also on record
- 3f9a12c0 · measurement · 14 decisions cost $0.00059, 318 ms each (p=0.41)

_1 entry not relevant to this task, omitted._

The rest is still saved. A different task brings back different things.

Install

Needs Node 22 or newer.

Claude Code

claude mcp add carryforward -e AI_GATEWAY_API_KEY=$AI_GATEWAY_API_KEY -- npx -y carryforward

Cursor, Claude Desktop, or any MCP client

{
  "mcpServers": {
    "carryforward": {
      "command": "npx",
      "args": ["-y", "carryforward"],
      "env": { "AI_GATEWAY_API_KEY": "...", "CARRYFORWARD_PROJECT": "my-project" }
    }
  }
}

The key is what reaches Jev. Without it everything still works, and recall just gives you the whole list and tells you it could not score.

Each project gets its own file. Claude Code starts the server inside your project, so this happens on its own. Desktop apps start it somewhere else, so set CARRYFORWARD_PROJECT per project or they all share one file.

Start every session with your rules already loaded. Add this to .claude/settings.json:

{
  "hooks": {
    "SessionStart": [
      { "matcher": "startup|clear|compact", "hooks": [{ "type": "command", "command": "npx -y carryforward recall --quiet" }] }
    ]
  }
}

What you can save

kind

what it is

needs a ref?

constraint

a rule or a boundary you set

no

correction

you corrected something the agent did

no

decision

a choice, and why you made it

yes

measurement

a number you will rely on later

yes

thread

work that is parked, blocked, or with someone else

yes

Constraints and corrections come back every time, in full. Jev never sees them, because a model should not get a vote on a rule you set.

The other three must point at something real: the command, the pull request, the commit, the file, the link. This keeps the list short, lets anyone check a claim instead of trusting it, and lets an entry fade away once the thing it points at is closed.

Each entry also saves where it came from: measured, decided, told, or inferred. So a guess never gets repeated later as a fact.

Write the what before the why. Entries are matched to a task by their words. One that only explains a reason will not be found by the task it belongs to. There is a real example of this below.

Why Jev

Jev is an evaluation model from TypeSafe. You give it some context and a typed question, and it answers with a probability. It writes no text at all.

That sounds like a limit until you notice this job never needs anything written. It only needs sorting. So the usual worry about a language model rewriting your notes or inventing a detail does not apply here, because Jev cannot write into your file even in principle. It reads and it ranks. Your words stay your words.

For each entry that is not a constraint or a correction, recall asks Jev one yes or no question:

Is this still live for the task starting now? Would not knowing it cause wrong or repeated work?

The probability that comes back decides what you see. Above 0.60 you get the full entry. Between 0.30 and 0.60 you get one line. Below that it is left out. Those numbers are exported constants, not hidden.

It is also cheap and quick. Jev costs $0.042 per million input tokens with no charge for output, so a list of a hundred entries is scored in four requests for well under a tenth of a cent, in about a second. carryforward reaches it through the Vercel AI Gateway, which is the route with published zero data retention terms.

Prefer a different scorer? Write an Asker with one ask(state, questions) method and pass it to recall(entries, task, asker).

A real run

Nine entries from a real project, three different tasks, 1.4 seconds each.

entry

"resume the email sign-in work"

"rerun the tests, which failures are real"

"add the scope check as a CI job"

email sign-in branch is parked

0.81

0.15

0.12

105 Windows test failures are environmental

0.27

0.81

0.21

the hook warns instead of blocking

0.20

0.15

0.41

PR #1903, written as "kept separate from #1860 because..."

0.22

0.12

0.17

the same fact, rewritten as "proposes the scope check as a CI check"

0.70

When an entry clearly fits the task it scores around 0.8, and nothing else comes close.

The last two rows are the same fact written twice. The first version only explains why the pull request exists and never says what it does, so Jev never connected it to the task. Rewritten to say what it is, it went from left out to shown in full. That is where the "what before why" advice comes from.

Nine entries and three tasks is a hint, not proof. There is no accuracy claim here until there is a proper test behind it.

What the eval suite found

evals/ holds a claude plugin eval suite, and the first thing it found was a hole in the design.

The payoff case gives the agent a real task, a branch rejected as behind main, and asks for the git commands. Nothing in the prompt mentions force-pushing. A rule recorded in an earlier session says never to force-push here, so the only route to the right answer is recalling it. The no-plugin arm is expected to fail. That gap is the measurement.

With the tools available and the skill installed, the agent called recall zero times out of four runs. Not blocked, not erroring, just never reached for. It answered a git question it already knew the answer to, and proposed a force push.

That is worth stating plainly: an MCP tool sitting there is not enough. An agent will not check a memory server before answering something it believes it knows, and a skill telling it to does not reliably change that. This is why the SessionStart hook exists and why it matters more than the tools do. The hook injects your rules unconditionally, at startup and again right after compaction, instead of depending on the model choosing to look.

Run it yourself. MCP tools are gated, so they need an operator grant on the command line, not just the case's allowed_tools:

claude plugin eval . --trust-plugin --ablation with-without \
  --allow-tools mcp__carryforward__recall mcp__carryforward__record

Mocks in evals/mocks/ stand in for the server, so runs are deterministic and never spend anything on scoring.

Things it will never do

  • It never deletes anything. Sorting happens when you read, not when you write. The file only grows.

  • It never scores your rules. Constraints and corrections always come back whole.

  • It never quietly gives you less. No key, no task, scorer down, rate limited: you get everything, plus a line saying why it could not sort.

  • It never sends anything when you save. Only recall with a task talks to the network, and your constraints and corrections are never part of that.

Where things are kept

One JSON line per entry, in ~/.carryforward/<project>.jsonl. Change the folder with CARRYFORWARD_DIR and the name with CARRYFORWARD_PROJECT.

Nothing is ever rewritten. To retire an entry you add a new one naming the old one, and the old line stays where it is. So a decision you reversed is still visible as reversed.

If a line ever gets damaged, by a crash or a full disk, it is skipped and counted, never removed, and recall tells you it happened.

Library and CLI

import { append, active, readAll, recall, formatBrief, gatewayAsker, ledgerPath } from "carryforward";

const path = ledgerPath();
append(path, { kind: "constraint", obtained: "told", text: "never force-push" });

const brief = await recall(active(readAll(path)), "add the scope check to CI", gatewayAsker());
console.log(formatBrief(brief));
npx carryforward              # run the MCP server
npx carryforward recall       # print what is saved, one line each
npx carryforward recall "..." # print what matters for this task
npx carryforward path         # show where this project's file lives

Help and contributing

Questions and bugs go in issues. Pull requests are welcome, and CONTRIBUTING.md explains the few rules that keep this small.

Two things are deliberately not built yet. Sorting as you write, a second small use of Jev that labels things as they happen so you do not have to decide what to save. And a proper accuracy test, comparing what was given to an agent against what it actually used. No accuracy number goes in this file before that exists.

npm install
npm run check

Tests use a fake scorer and never touch the network.

License

MIT

Available Tools

2 tools
recallRecall for a taskA

Bring forward what earlier sessions recorded, scored against the task you are about to do. Call it once, at the start of a task, with the task in one sentence. Constraints and corrections come back in full every time. Everything else is scored for whether not knowing it would cause wrong or repeated work: high scores come back in full, middling ones as one line, the rest are omitted. Without a task it lists everything one line each. If scoring is unavailable it returns everything and says so — it never returns less than the ledger holds without telling you.

ParametersJSON Schema
NameRequiredDescriptionDefault
taskNothe task about to start, in one sentence

TDQS

A4.8/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations provided, the description carries the full burden and does so thoroughly. It discloses what comes back in full, what is truncated to one line, what is omitted, what happens without a task, and how it behaves if scoring is unavailable. This is unusually explicit about output and failure behavior.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is dense but every sentence earns its place: it explains purpose, invocation, ranking behavior, the no-task mode, and the fallback guarantee. It is front-loaded with the core function and does not waste words.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With no output schema, the description must explain return behavior, and it does so completely: full returns, one-line returns, omissions, no-task listing, and degradation when scoring is unavailable. For a one-parameter recall tool, nothing essential is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters5/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Although the schema already documents the 'task' parameter, the description adds crucial semantics: the task should be one sentence, it is optional, and omitting it changes the result entirely to a one-line-per-item listing. This goes well beyond the schema's description.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states a specific action ('bring forward what earlier sessions recorded') and the resource it operates on, and it is clearly the read-side counterpart to the sibling tool 'record'. It goes beyond the name and title by explaining the scoring behavior, so an agent cannot mistake it for a generic recall tool.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description gives explicit usage instructions: 'Call it once, at the start of a task, with the task in one sentence' and also explains the no-task variant. It does not explicitly say when not to use it or contrast it with the sibling 'record' tool, so it falls just short of full alternative-route guidance.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

recordRecord to the ledgerA

Append one fact to this project's ledger, at the moment it is produced. Call it right after: the user states a rule or a boundary (constraint); the user corrects something you did (correction); you choose between alternatives (decision — say why in text, and ref where it is recorded); a tool result yields a figure you will rely on (measurement — ref the command, refresh says whether it reproduces); work is parked, blocked, or handed to someone (thread — ref the branch, PR, or issue). Decisions, measurements and threads must carry a ref. Write text so it says WHAT the thing is before WHY: recall scores entries against a future task by their text, and an entry that only explains a reason will not be found by the task it belongs to. To retire an earlier entry pass its id in supersedes; the old entry stays on disk, marked replaced. Nothing here is ever deleted.

ParametersJSON Schema
NameRequiredDescriptionDefault
refNowhat it points at: a command, PR, issue, commit, file path or URL. Required for decision, measurement, thread
kindYesconstraint | correction | decision | measurement | thread
textYesthe claim, one or two sentences; say what it is, then why
refreshNohow to re-derive it, or the words 'not reproducible'
obtainedYeshow the claim was obtained: measured | decided | told | inferred
supersedesNoid of an earlier entry this one replaces

TDQS

A4.8/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations are provided, so the description must carry the full burden. It does: it discloses persistence ('Nothing here is ever deleted'), the replacement behavior ('the old entry stays on disk, marked replaced'), and the rationale for text formatting to support future recall. These are non-obvious behaviors an agent needs to know.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is longer than typical but every sentence serves a purpose: it front-loads the core action, then provides the when-list, then per-field semantics and lifecycle rules. It is structured as a compact reference, not padded prose. Slight verbosity is justified by the tool's complexity.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a 6-parameter tool with two enums and no output schema, the description covers all necessary aspects: when to invoke, what each field means, required ref conditions, text formatting rules, supersede semantics, and the permanence guarantee. It also implicitly contrasts with recall. Nothing an agent needs to call correctly is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, so every parameter already has a description. The description adds value beyond that by explaining the semantic role of each field in context: e.g., 'ref' is required for specific kinds, 'text' should lead with WHAT for recallability, 'refresh' indicates reproducibility, and 'supersedes' links to an earlier entry. This enriches the schema without redundancy.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description opens with a clear verb-resource pair ('Append one fact to this project's ledger') and specifies the exact timing ('at the moment it is produced'). It distinguishes itself from the sibling tool recall by framing this as the write operation ('recall scores entries against a future task'), so an agent can tell them apart without inspecting schemas.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description enumerates specific trigger conditions ('Call it right after: the user states a rule or a boundary... the user corrects something... you choose between alternatives...') and gives explicit formatting guidance ('say what it is, then why') plus rules for required refs per kind. It also explains when to use supersedes to retire an entry. This is explicit and actionable.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

  1. 2 tool updatesv0.1.1
    • First observedrecall
    • First observedrecord

TDQS

A4.9/5.0

Scored across 2 tools

Disambiguation5/5

Record and recall have completely distinct purposes: one appends to the ledger, the other queries it. There is no overlap or ambiguity between them.

Naming Consistency5/5

Both tools use the same pattern of a single imperative verb describing the operation. Record and recall are symmetric, predictable, and easy to distinguish.

Tool Count5/5

Two tools perfectly cover the core write/read lifecycle of the ledger. Additional tools would add bloat without expanding the server's stated purpose.

Completeness5/5

The surface supports recording facts, superseding old entries, task-scored recall, and full listing without a task. Deletion is intentionally excluded by design, so no necessary operation is missing.

Maintenance

ActivityMaintained
ResponsivenessNo issues

Related MCP Connectors

Related MCP Servers

  • A
    license
    Not graded
    quality
    A
    maintenance
    Provides persistent project memory for AI coding agents, enabling context retention across sessions via event logging, briefing generation, and querying.
    MIT
  • A
    license
    Not graded
    quality
    A
    maintenance
    Enables MCP agents to maintain durable, evidence-aware project knowledge, retrieve precise excerpts on demand, and track decisions, conflicts, and revisions across sessions.
    1
    Apache 2.0
  • A
    license
    Not graded
    quality
    B
    maintenance
    Enables coding agents to persist and retrieve cause-effect project memories across sessions using a local ledger and hosted ranking tools, with corrections always prioritized and unreliable answers suppressed.
    695 npm
    MIT