What Letta Code records, and what it does not

Read ate0a0e1e
Repositorygithub.com/letta-ai/letta-code
LicenceApache-2.0
Assessed asstores, acts
Reachesno level yet
Read byTroy Brandon Clifford
LevelMeetsWhat the level asks
TR-1 Recorded3/5The record exists and is append-only.
TR-2 Explained0/4Every belief resolves to its evidence, and disagreements survive.
TR-3 Gated3/7Actions carry a verdict, and approvals carry a name.
TR-4 Verifiable1/3The record can be shown not to have changed.

A count is requirements fully met out of those that apply. This system is assessed as stores, acts, and requirements outside that are not counted against it.

The memory here is a git repository, and that one decision answers most of TR-1 by itself: every memory write is a commit, so nothing is overwritten, every prior version is readable, and the history has an author. It is the only assessed system whose store is content-addressed by construction, which puts it closer to TR-4 than anything else in this census. Two things stop it going further and both are deliberate. Commit signing is not merely absent but explicitly disabled, in memory-git-signing.ts, because the harness-managed committer identities have no key, so a rewritten history is indistinguishable from an original one to anyone who did not record a SHA beforehand. And git's durability cuts the other way on erasure: deleting a memory is a commit, which records the deletion and keeps the deleted content in history, so honouring a real erasure request means rewriting the history that was the point of using git. The approval flow could not be settled from this repository and is marked accordingly rather than assumed.

Every verdict, and what it rests on

Twenty requirements, each stated as a capability rather than a format, so a system that holds the information in its own shape counts as having it. An absent verdict cites where the assessor looked and did not find it, which is the difference between a measurement and an accusation.

TR-1 Recorded

The record exists and is append-only.

R1.1 · present. When the system stores a fact, does it durably record when that happened?

  • source src/agent/memory-git.ts:67-82
    a memory commit carries a MemoryCommitAuthor with authorName and authorEmail and a committed flag; git records author and committer dates on every commit
  • source src/agent/memory-git.ts:10-11
    the module header describes its job as "pull on startup, commit memory writes, post-turn push for clean pending commits", so a memory write is a commit and inherits its timestamp

R1.2 · present. When a stored fact changes, is the previous version still readable?

  • source src/agent/memory-git.ts:10-11
    memory writes are commits in a git repository, so each edit produces a new revision and every earlier one remains readable through ordinary git history
  • source src/agent/memory-git.ts:861
    "Ensure local main tracks only origin/main and direct commits use the agent identity", so the chain of revisions is maintained rather than collapsed

R1.3 · present. Does the ordinary write path ever destroy what was previously recorded?

The strongest answer to this requirement in the census, and the one obtained most cheaply: using git means append-only was never a thing that had to be built.

  • source src/agent/memory-git.ts:10-11
    the ordinary write path edits a memory file and commits it; git retains the previous blob, so nothing recorded is destroyed by a write
  • source src/agent/memory-git-hooks.ts, referenced at memory-git.ts:915-917
    a post-commit hook pushes to the configured mirror after every commit, so the history leaves the machine as it is made

R1.4 · partial. Are entries distinguishable by kind, or is everything one undifferentiated blob of text?

Files are distinguishable from one another. A claim and its source are not distinguishable within a file, because both are prose.

  • source src/agent/memory-filesystem.ts and src/agent/memory-markdown.ts
    memory is markdown files on a filesystem, so different files are different documents and the format has internal structure
  • searched grep -rniE 'source|provenance|citation' src/agent/memory-format.ts src/agent/memory-markdown.ts
    no match; there is no record type distinguishing a claim from the material it rests on

R1.5 · partial. When data must be destroyed for a legal reason, is the destruction itself recorded?

The trace is excellent and the other half fails in the way git always fails it: the deleted content stays in history, and on any mirror it was pushed to. Satisfying a real erasure request means rewriting the history, which destroys the record that made this requirement passable. This is the same bind mem0 is in, reached from the opposite direction.

  • source src/agent/memory-git.ts:10-11
    removing a memory is a commit like any other, so the removal is recorded, dated and attributed
  • source src/agent/memory-git.ts:915-917
    the post-commit hook pushes every commit to the configured mirror, so the content being erased has usually already left the machine before the erasure is requested

TR-2 Explained

Every belief resolves to its evidence, and disagreements survive.

R2.1 · absent. Can the source a stored fact came from be recovered from the store, by following a link rather than by guessing?

The commit history says when a memory appeared and which agent identity wrote it. That is closer to provenance than most systems here manage, and it is still not a link to the source: reading a memory gives no way to reach the conversation that produced it.

  • searched grep -rniE 'source|provenance|citation' src/agent/memory-format.ts src/agent/memory-markdown.ts
    no match; the memory format carries no field or convention linking a written memory to the message or file it came from
  • source src/agent/memory-git.ts:67-82
    the commit author identifies which agent wrote the memory, which is who recorded it rather than what it was drawn from

R2.3 · partial. When two stored facts about the same proposition disagree, do both survive?

Both survive as history because git keeps everything. Only one survives as memory: reading the current file gives the latest text, and finding what it replaced means reading the log.

  • source src/agent/memory-git.ts:10-11
    an agent revising a memory produces a commit, so the superseded text remains in history
  • searched grep -rniE 'conflict|contradict' src/agent/memory.ts src/agent/memory-format.ts src/agent/memory-runtime.ts
    no match; nothing detects that two statements disagree, so a revision that contradicts an earlier memory is an ordinary edit

R2.4 · absent. Is the disagreement itself queryable, or must a reader diff rows to notice it?

  • searched grep -rniE 'conflict|contradict' src/agent/memory.ts src/agent/memory-format.ts src/agent/memory-runtime.ts
    no match; there is no conflict record, marker or listing. Git surfaces merge conflicts between branches, which is a different thing from two memories disagreeing about a fact

R2.5 · partial. When a conflict is resolved, does the record say who resolved it and by what method?

There is an actor on every change, which is more than most systems here record. The actor is the agent, and since nothing recognises a disagreement in the first place, there is no method recorded for how one was settled.

  • source src/agent/memory-git.ts:67-82
    every memory change carries an author, so a revision that supersedes an earlier claim is attributed to whoever made it
  • source src/agent/memory-git.ts:894-900
    the committer identity is harness-managed, described in memory-git-signing.ts as <agentId>@letta.com or noreply@letta.com, so the attribution names an agent rather than a person

R2.2 is not assessed here, because this system is not in that business and marking it down for that would be dishonest.

TR-3 Gated

Actions carry a verdict, and approvals carry a name.

R3.1 · present. Does a consequential action produce a durable entry whether or not it ran?

A proposed action that has not run is a durable record, not a run-scoped one, and the harness depends on that being true in order to resume.

  • source src/agent/check-approval.ts:26-34
    approval_request_message and approval_response_message are first-class message types, listed in RESUME_BACKFILL_MESSAGE_TYPES
  • source src/agent/check-approval.ts:2
    the module exists to "Check for pending approvals and retrieve recent message history when resuming an agent/conversation", so an approval pending at shutdown is fetched back afterwards, which is direct evidence that the record survives the process

R3.2 · present. Does an action's risk class come from somewhere the proposing model cannot write to?

Binary rather than graded, like every other framework assessed here, and set outside anything a plan can write, which is the substance of the requirement.

  • source src/tools/manager.ts:1118-1139
    a tool's permissions carry requiresApproval, derived as approvalPolicy !== "auto" and surfaced as "ask" or "auto"; the policy sits on the tool rather than in the model's output

R3.3 · present. Are refusals recorded as faithfully as permissions?

The only system in this census where a refusal has its own record type rather than being narrated into a tool result.

  • source src/agent/check-approval.ts:26-34
    approval_response_message is its own message type, so a refusal is recorded as a distinct kind of thing rather than as an error or a string, and is backfilled on resume like any other

R3.4 · partial. Does a refusal record why it was refused?

A reason has a defined place and survives into the record, which is better than CrewAI discarding it or LangGraph never modelling it. It is optional and it arrives as prose inside a tool return rather than as a field, so it cannot be relied on or read mechanically.

R3.5 · undetermined. Does an approval identify a person or a named role holder?

This is the one system in the census where the answer might be yes, and it cannot be settled from the source available. An acting-user identity exists, is server-validated, and is explicitly designed to name the human rather than the credential, which is precisely what this requirement asks for. Whether it lands on an approval response is not visible here. Recording that honestly is worth more than guessing in either direction, and the Letta maintainers can close it in one sentence.

  • searched find . -type d -name letta-client; ls vendor
    the approval_response_message type is defined in the @letta-ai/letta-client dependency and the message store is the Letta server. Neither is in this repository, so the fields carried on an approval response cannot be read here
  • source src/agent/acting-user.ts:1-13
    evidence pointing towards a person being identifiable somewhere: X-Letta-Acting-User-Id exists so cloud-api can "re-attribute requests to the human who actually initiated them (rather than the user whose API key spawned the sandbox / desktop runtime)", and cloud-api validates listener origin and org membership before honouring it
  • searched grep -rn 'ACTING_USER_ID_HEADER' src/agent/
    the header is described as stamped onto input, execute_command and conversation_create frames. Approval responses are not named among them, and whether the acting user reaches the approval record is a question about the server

R3.6 · undetermined. Does the approver's identity come from the authentication layer rather than from something the model can write?

The mechanism that would satisfy this requirement demonstrably exists and is validated in the right place. What is unverifiable from here is whether it is applied at the approval boundary.

  • source src/agent/acting-user.ts:5-11
    the acting user id is not taken on trust: "Cloud-api validates listener origin + org membership before honoring it", which is identity established by the server rather than asserted in a request body
  • searched find . -type d -name letta-client; ls src/backend/local
    no message persistence exists in this repository and the client types are not vendored, so whether an approval record carries that validated identity cannot be checked here

R3.7 · undetermined. Is the acting agent prevented from approving its own action?

  • searched grep -rniE 'approver|approved_by|principal' src/agent/approval-execution.ts src/agent/check-approval.ts
    the harness sends an approval decision and does not itself model principals, so whether the server refuses an approval originating from the acting agent's own credential is not decidable from this repository
  • source src/agent/acting-user.ts:1-5
    the header exists specifically to distinguish the human who initiated a request from "the user whose API key spawned the sandbox / desktop runtime", which is the same distinction this requirement turns on

TR-4 Verifiable

The record can be shown not to have changed.

R4.1 · partial. Does the system publish a scheme under which the record's past state can be verified?

The substrate provides a real integrity structure and the implementation neither publishes it as one nor takes the step that would give it force. The reason for disabling signing is sound: the harness-managed committer identities have no key, so a global commit.gpgsign=true would break memory initialisation outright. The consequence is still that nothing attests to who made a commit beyond a string in the author field.

  • source src/agent/memory-git.ts:10-11
    memory is a git repository, so the history is a chain of content-addressed commits, each naming its parent. That is a hash chain in structure, obtained as a side effect of the storage choice
  • source src/agent/memory-git-signing.ts:1-15
    "Memory-repo commits must never be signed." GIT_DISABLE_COMMIT_SIGNING_ARGS passes -c commit.gpgsign=false as highest-precedence config on every harness git invocation, so no commit carries a signature
  • source src/agent/memory-git.ts:894-900
    the same default is written into the repo's local config, so even direct git commit runs inside the memory repo are unsigned

R4.2 · present. Can an independent party run that verification without the vendor's cooperation, and without the operator's?

Whatever verification the format supports can be run entirely by the record holder against their own clone. That is the requirement, and using git means it is satisfied by every tool the reader already has.

  • source src/agent/memory-git.ts:912-924
    the memory repository's mirror URL lives in the repo's local .git/config under letta.memoryRepository.url and is configured by the user through a slash command, so the holder can keep their own copy
  • source src/agent/memory-git.ts:10-11
    the history is an ordinary git repository, so git log and git fsck answer against it with no vendor involvement, no hosted service and no key the vendor holds

R4.3 · partial. Would alteration of a past entry be detectable after the fact?

Closer to tamper-evidence than anything else assessed here, and short of it by one step. The push mirror is already most of an external anchor; recording the pushed head somewhere the harness cannot force-push would finish the job without changing the write path at all.

  • source src/agent/memory-git.ts:10-11
    editing a past commit changes its object id and every descendant id, so an alteration is detectable by anyone holding a previously recorded SHA
  • source src/agent/memory-git-signing.ts:1-15
    with signing disabled, a rewritten history is internally valid and carries no attestation, so a fresh clone cannot tell a rewrite from an original
  • source src/agent/memory-git.ts:915-917
    the post-commit hook pushes to the configured mirror after every commit, which is an anchor in practice if the mirror is somewhere the agent cannot rewrite

How this was read

Read of src/agent/memory-git.ts, memory-git-signing.ts, memory-git-hooks.ts, acting-user.ts, check-approval.ts, approval-result-normalization.ts and src/tools/manager.ts at e0a0e1e, cloned from the public repository. Line numbers are that commit's. SCOPE: this repository is the harness. Agent messages, including approval requests and responses, are held by the Letta server, which is not in it. Requirements that turn on the shape of that record are marked undetermined rather than guessed, and say so.

Found an error? Challenge a finding

Then it is wrong in the ordinary way readings are wrong, and every verdict cites a file and a line at a pinned commit precisely so that being wrong is cheap to demonstrate. The remedy is a pull request against the subject file, and it does not involve persuading anybody. Nobody applied for this and it is not a certification.

The standing register carries every system side by side, and the rubric is the twenty requirements in full, free to apply to anything, including to this assessment.