A Debt Is Not a Rule: Agent Memory Needs a Paid State
Some agent memory notes are always true; others are true until something gets done. Give both one lifecycle and one kind breaks. A debt needs a paid state: a condition, checked by the system, that says when it is settled.
Two notes about one repository. "config/app.yaml is generated from templates/app.yaml.j2: edit the template." "tests/test_retry.py is flaky until it uses the frozen_clock fixture." Both are caveats about a single file, both should reach a coding agent when it touches that file, and nothing in either sentence tells a memory store that they end differently. vectr, the memory tool I build, files both under one kind in the instructions it installs for the agent: a caveat tied to one file, "this test is flaky" or "this config is load-bearing", is a gotcha.
The first note is true for as long as the file is generated. Obeying it does not use it up; the agent that followed it yesterday needs it again today. The second is true until one change lands, and false from then on. Call the first a rule and the second a debt.
Give both one lifecycle and one of them breaks. Under a debt's lifecycle, which counts every warning that was not followed by a fix, a rule that is obeyed every time piles up misses until it escalates into a block. Under a rule's lifecycle, a debt warns forever, no louder while it is owed and no quieter once it is paid. hipocampo, an open-source hook system by JhouCode, hit the first failure in its pilot and split the two kinds. vectr has the second failure: a debt there warns until someone remembers to retire it by hand.
What is missing is a paid state. A debt should carry the condition that settles it, written so that a program can evaluate it, and die when the condition holds. The agent reporting that it fixed the test does not count.
Rules and Debts in Agent Memory: Two Notes That End Differently
Most of the engineering in agent memory goes into delivery: which hook, which trigger, how many tokens. Rules and debts differ at the other end, in when a note should stop arriving.
A rule describes a standing property of the workspace. "config/app.yaml is generated: edit the template." "After changing api/schema.py, run make client so the generated API client matches." Nothing the agent does makes a rule false, so respecting it once does not retire it.
A debt describes a gap with a known way of closing. "tests/test_retry.py is flaky until it uses the frozen_clock fixture." "The retry path in client/http.py has no test." Each is true until a particular change lands. Delivered after that, a debt describes code that no longer exists, and an agent that believes it may add a retry loop or a skip marker to a test that now passes.
The way to tell them apart at write time is to ask what would make the note unnecessary. For the generated config, nothing the agent can do. For the flaky test, one event: the test starts using the fixture. If a program can detect that event, the note can carry the check, and the memory system can decide for itself when the note is done.
Software engineering has studied this object for a decade. A TODO or FIXME comment beside code its author knows is not right yet is self-admitted technical debt, a term the later literature credits to Potdar and Shihab (2014). A debt in an agent's memory is the same thing kept elsewhere, and nothing ties its text to the change that would settle it either.
A building has two signs. "Mind the step" is a rule: true for as long as the step exists, and nobody takes it down because people minded the step. "Wet paint" is a debt: true until the paint dries. Treat both alike and either "mind the step" comes down after a month because it looks old, or "wet paint" stays up for a year and people learn to lean on walls with signs on them.
The analogy fails in an instructive place. Paint dries on a schedule, so for wet paint a clock really is a fair stand-in for payment. Few debts in a codebase have a schedule. A flaky test does not fix itself after 30 days.
One Memory Lifecycle, Two Failures: Escalating Rules and Immortal Debts
A debt needs escalation. A warning that can be ignored forever at no cost is a log line, and debts do get ignored. hipocampo's dispatcher opens by noting that the files named in its original backlog "received dozens of commits while their items stayed open". After three ignored warnings, the fourth touch should cost something, such as a request for approval before the change goes through.
A rule must never escalate. Escalation punishes a touch that left the note in place, and for a rule that is what obedience looks like. The make client rule is touched on every edit to api/schema.py and can never be paid. An always-obeyed rule should produce zero blocks.
Rules under a debt's lifecycle
An escalation ladder has a charging step that runs when a turn closes and decides, for each note it warned about, whether the warning was acted on. Without a payment condition, all it sees is that it warned, the anchored file was written and the turn closed. For a debt that is a fair proxy for a missed chance to pay; for a rule it is compliance. An agent that edits api/schema.py and then runs make client leaves exactly the same trace as one that edits the schema and moves on. A Directive Is Not a Memory makes the general point that obeying a directive destroys the evidence that would test it; under a debt's lifecycle the same blindness turns an obeyed rule into an unpaid debt.
For one note and sessions s = 1, 2, ..., let ws mean the note was delivered in session s, es that its anchor file was written, and ps that the debt was settled by the end of the session. The counter a ladder needs, with θ the number of misses at which it starts asking, is:
Without a paid state ps is invisible, so the counter that actually runs is:
A rule is never settled, so its mobs is just the number of sessions that wrote the file. With θ = 3, an always-obeyed rule asks before every write from its fourth writing session on. A paid state stores a predicate C and sets ps = C(workspace at the end of s), which gives debts back the counter they need. Rules stay out of the count.
Debts under a rule's lifecycle
Under a rule's lifecycle a debt warns at the touch, every session, and that is all. While it is owed, ignoring it is free, so the tenth warning weighs what the first did. Once it is paid, the flaky-test note keeps arriving until somebody notices and deletes it.
The two failures are not equally expensive. A rule misread as a debt fails loudly, because every ask stops a person to approve a change that was correct. A debt misread as a rule fails quietly, at the price of a few stale lines per touch and the occasional wrong turn. That difference decides the default. When the kind is unclear, a rule is the cheaper mistake.
| Property | Rule | Debt |
|---|---|---|
| True until | the workspace loses the property | a specific change lands |
| A touch that leaves it in place | the rule was in play, usually obeyed | a missed chance to pay |
| Escalation | never | warn, then ask before the change |
| Correct end | none while the property holds | paid, when its condition holds |
A single lifecycle gets one of the highlighted rows wrong for one of the two kinds.
hipocampo Split Debts From Rules After Its Pilot
hipocampo is an MIT-licensed hook system for agent memory by JhouCode. Its dispatcher, scripts/gatilho.py, reads markdown tables in which each row ties a path or command regex to a sentence for the agent, and counts rides per row. It runs on three hook events that form a ladder:
- D1 warn, on PostToolUse: the row speaks at the touch, once per session.
- D2 charge, on Stop: a row that was warned about and written, but not paid, gets one more ride.
incrementa_caronawrites the new count into the table itself, so it shows up in the git diff. - D3 block, on PreToolUse: at
TETO_D3rides, which is 3, the hook returnspermissionDecision: "ask", and "the touch does not pass without the owner's decision".
"Promotion belongs to the COUNTER, not to the agent," the module header says. No step waits for the agent to notice that the step before it failed.
The ladder was built for a backlog of debts, and the pilot found a second kind of row. The docstring of e_regra records it:
"SECOND PILOT FINDING, deeper than the first. The sources have two kinds of item and only one had been designed: DEBT (the
backlog) -- dies when paid. Accumulated rides = debt coming due, and escalating to D3 is the right answer: at some point it has to hurt. RULE (dependencia,duplicado) -- does NOT die. "Check the projection before editing" holds every time, forever. Counting rides as debt would bring every rule to 3 and make it block everything, even when the rule is always obeyed -- because D2 only knows that it warned, there was a write and the turn closed; it does not know whether it was paid.""For a rule, the counter is a METRIC: a high number says "this rule lives on my path, it is worth revising or automating", not "time to block"."
The code matches the docstring. d2_cobra still increments a rule's rides but records its state as regra and leaves it out of the charged list, and d3_barra drops every rule before deciding to ask. The memory source puts remembered knowledge on the rule side: "Every item here is a RULE -- there is nothing to "pay"."
How hipocampo knows a debt is paid
A row is paid when its id is struck through. The parser sets it["pago"] from whether the id starts with ~~, and the backlog's contract says the struck row "stays in the table as proof that the trigger worked". Payment is declared by whoever edits the table. The charging step has no way to tell whether the test stopped flaking; it can tell whether someone typed two tildes. In a system that refuses to guess, that is the honest choice, and the remaining question is which declarations a check could replace.
vectr Gives File-Anchored Notes One Lifecycle and Ends Them Only by Hand
At commit 726e798 on its public main branch, vectr has seven note kinds (VALID_KINDS); the instructions it installs describe six and leave out operational. A kind sets delivery through a default trigger bundle. Directives load at session start and after compaction, high-priority tasks at session start, gotchas when their anchor file is touched, and operational notes on a semantic match with the prompt. The other three kinds wait for recall. No kind says how a note ends.
Session hooks: once per session, every session
Through the session hooks, a gotcha fires the first time in a session that a file tool is about to read or edit its anchor. The event is named pre-edit, and the hook sends Read calls to it too. TriggerFireLedger then suppresses that trigger "for the rest of the session"; compaction resets it, and a new session gets a new ledger. Nothing counts whether the warning was followed, and nothing ends the note. That is a rule's lifecycle. It suits "this config is load-bearing" and turns "this test is flaky" into a debt that warns forever.
The proxy: retirement on the first edit
vectr also ships an experimental local proxy that adds matching notes to requests on their way to the model. Release 1.7.0 (29 July 2026) gave it "Event-anchored retirement": a note delivered for its declared anchor "now stays eligible for re-delivery while its file is merely being read, and retires the first time a request's window shows the file actually edited."
In the code, "retires" means "enters the cooldown". A file counts as edited when a tool call named Edit, Write, MultiEdit or apply_patch targets it within the last 20 messages of the request (request_window.py). Until then, gate.py delivers the note without recording it in the cooldown ledger; from then on, each delivery is recorded. The ledger keeps the last 30 delivered ids and lets an entry go once its latest delivery is an hour old (cooldown_items: 30, cooldown_ttl_seconds: 3600), so a retired note can be back within the hour.
For the flaky test that timing is plausible, since an edit to the test is when a fix would land (an edit that only renames a variable retires it just as well). For a rule it runs backwards. Anchor the generated-config rule to config/app.yaml. An agent that obeys edits the template, the anchor never shows as edited, and the note goes out on every matching request. An agent that disobeys edits config/app.yaml, and that violation is what puts the note into cooldown. It arrives once more, after the fact, and a second bad edit within the hour gets nothing from the proxy.
What can end a note
Every way to end a note in vectr is a call someone has to make. vectr_forget deletes the row and its event log, so the record that the debt existed goes with it. vectr_revoke is for a note "proven wrong", and a paid debt was right when it was written. Supersession fits best. A note named in a later note's supersedes field "is excluded from recall/fire from now on but retained, unchanged, for audit", and vectr_supersede, added in 1.11.0, does the same after the fact, with or without a successor. Its tool description says the retired note "was accurate when written; the world moved on". vectr_reinstate undoes revocation and supersession; nothing undoes a delete.
So vectr can retire a paid debt by declaration, as hipocampo does with tildes. Someone has to remember the note, check the code and make the call, and when that someone is the agent, its word is the evidence. For one kind, the store's hygiene code admits the gap. stale_task_summary notes that "a task note left un-superseded keeps firing at every session-start forever", and vectr_status prints a reminder that "age alone never retires a note" once three or more task notes older than seven days are live (the thresholds). Gotchas get no reminder.
Time-Based Memory Expiry Is a Clock Standing In for Payment
A system that cannot tell when a note is done falls back on time. vectr's triggers accept three "temporal guards (not_before, expires_visibility, cooldown)". In evaluate_note, the first holds a note back until a time and the third for some seconds after it fired. expires_visibility "never withholds"; it "only marks the result faded for ranking", and the result type says "the caller should rank/pack it as faded". No caller does at this commit. Outside the trigger engine only its tests read faded, so a note past its visibility time is delivered as before.
There is also a TTL table by kind: 60 days for operational, 90 for task, 120 for gotcha and finding, 180 for reference, 240 for decision, none for directive. Expiry appends an event rather than deleting, and vectr_reinstate reverses it. The table does less than it suggests. Startup runs expiry only when VECTR_NOTES_TTL_DAYS is set, and that value replaces the TTL of every kind not exempt from expiry. By default nothing expires. With the variable set, every non-directive note expires at the same age.
A clock is a fair stand-in for payment when the debt has a schedule: wet paint, a migration window that closes on a date. A flaky test has none.
Let T be the TTL in days and d the day the debt is actually paid. The TTL cannot see d, so it errs in one direction or the other:
Take the 120 days the table gives a gotcha. Fix the test on day 3 and the note runs for 117 more days; fix it on day 200 and it was hidden for the last 80 days it was true. Both terms are zero only when T = d, and picking that T means knowing d in advance.
A guide to memory lifecycle policies on the AWS Machine Learning Blog puts the trade-off plainly: "TTL does not consider whether a memory is still useful, but it provides a hard ceiling on accumulation and is essential for compliance." A ceiling on accumulation is worth having. It does not say whether a debt is settled.
Anchor drift
One vectr signal moves with payment. check_staleness flags a note when a file it references was modified after the note was written, or no longer matches the content hash stored with it. The flagged note is still delivered, marked as changed. For the flaky test, drift means the file was edited, which payment requires and does not prove. For a note on a generated file it means nothing, because the file changes every time its template does.
Removing the TODO Is Not Paying the Debt: What SATD Research Measured
Research on self-admitted technical debt has measured what happens when the marker of a debt disappears, and the answer should worry anyone who treats a note's disappearance as payment.
Maldonado, Abdalkareem, Shihab and Serebrenik (ICSME 2017) followed SATD comments through the history of five open-source Java projects and defined removal by the comment: "When the comment is no longer found, we mark that version of the file as the removal version." By that definition most of the debt went away, on average 74.4% (median 76.7%), after lasting "between 82 - 613.2 days on average". Their survey of 14 developers found "no formal process to remove self-admitted technical debt".
Zampetti, Serebrenik and Di Penta (MSR 2018) took that removal dataset and read the code changes behind 1,691 removals. They report that "between 20% and 50% of SATD comments are accidentally removed while entire classes or methods are dropped", and that only "8% of the SATD removal is acknowledged in commit messages." Some comments disappeared from methods that did not change at all: under 8% of removals in four projects and 17% in the fifth. Earlier work, they note, had interpreted removal "as removal of the comments reflecting SATD rather than removal of the code affected by the SATD."
A memory note that is forgotten, expired, cooled down or superseded is a comment that disappeared, and whether its debt was paid is a separate fact, one Zampetti and colleagues had to establish by reading changes by hand. The percentages describe human developers on Java code and should stay with them. What transfers is the measurement error of counting the marker instead of the debt.
Classify Each Agent Memory Note by What Would Make It Unnecessary
Nothing proposed in sections 07 to 10 is in a vectr release, and none of it has been measured.
At write time, whoever writes the note, agent or person, answers one question: what would make this note unnecessary? There are three answers.
- An event a program can check. The note is a debt and stores the condition:
tests/test_retry.pycontainsfrozen_clock;scripts/deploy.shno longer containssleep 30;pytest tests/test_http_retry.pyexits 0. - An event no program can check. "Rotate the signing key at the next release." The note is a debt whose payment has to be declared, which is how hipocampo handles every debt. It should not get an invented condition: hipocampo's backlog warns that a weak regex for an item with no real trigger "would leave the source green and blind", and a weak payment condition would do the same to a debt.
- Nothing. The note is a rule.
A debt's condition should fail at the moment the debt is written. If it already holds, either the debt is paid or the condition is wrong, and the store should reject it rather than file a debt that would die on its first touch. When the answer is unclear, store a rule; the two mistakes cost different amounts.
Let θ be the escalation threshold. A rule's anchor is written in W sessions; a debt's anchor is touched in T sessions and the debt is paid in session P.
Each false ask stops a person to approve a correct change. With θ = 3, a rule on a file written in 40 sessions produces 37 interruptions, and a debt paid in session 4 of 40 produces 36 stale warnings. The counts are close, but an interruption costs a person's attention and a stale warning costs a few lines of context.
Lifecycle as its own field
vectr's kinds decide delivery and should go on doing that. A gotcha can be a rule or a debt, and so can a task, though most tasks are debts. The lifecycle goes in a separate field, read as rule when absent or unrecognised, so every existing note keeps its current behaviour:
{
"kind": "gotcha",
"lifecycle": "debt", # "rule" when absent or unknown
"content": "tests/test_retry.py is flaky until it uses the frozen_clock fixture",
"anchors": [["tests/test_retry.py", "<content hash at write>"]],
"condition": {"file_contains": {"path": "tests/test_retry.py",
"pattern": "frozen_clock"}},
"state": "owed", # owed | paid
"misses": 0,
"fires": 0
}
Conditions that run code
File predicates (exists, contains, no longer contains) take microseconds and execute nothing. A command condition such as "this test passes" is closer to the real debt and riskier, because it turns note text into something that runs, and notes reach a store from many hands. vectr already records note provenance, ordered auto, agent, human, and release 1.7.0 uses it to choose how skeptically the proxy introduces a note. A command condition should be accepted only on a note a human has endorsed, run read-only with a timeout, and count a timeout as not paid, so a hung check leaves the debt warning.
A Debt Counts the Touches That Did Not Pay It, and Dies When Paid
A debt is owed or paid, and its condition is checked at two moments.
- On touch. When a tool is about to read or edit the anchor, check the condition. If it holds, record the payment and deliver nothing. Otherwise deliver a warning, or, once the debt has θ misses and the tool is about to write, an ask before the write, which JhouCode calls "the other half of the escalator: a
PreToolUsethat returnspermissionDecision: "ask"once a warning has been ignored." - When the turn closes. For each debt delivered this turn whose anchor was written, check again. If the condition holds, it was paid this turn; if not, add a miss.
The turn-close check needs the set of paths written during the turn, gathered from post-tool events. Shell commands write files without any file tool, just as they read them (Agents Read Files Through the Shell measures the reading side), and those writes slip past that set. The touch check covers them, because it reads the workspace rather than the event stream. A debt paid by a shell edit, a merge or a colleague's commit shows up as paid at the next touch, however the payment arrived.
def on_touch(note, path, ws, is_write=False):
if note.lifecycle != "debt": # rules, and anything unknown
note.fires += 1
return deliver(note, level="warn")
if note.state == "paid":
return None
if check(note.condition, ws): # lazy: this note, this moment
mark_paid(note, ws) # nothing delivered
return None
level = "ask" if is_write and note.misses >= THETA else "warn"
return deliver(note, level=level)
def on_turn_close(delivered, written_paths, ws):
for note in delivered:
if note.lifecycle == "debt" and note.anchor in written_paths:
if check(note.condition, ws):
mark_paid(note, ws) # paid in this turn
else:
note.misses += 1
A recorded death that can be reversed
A paid debt is the plainest case for Forgetting Is a Capability, Not a Failure, since a note whose job is done should leave delivery on purpose. It should not be deleted. mark_paid appends a transition with the time, the commit the working tree was at, the condition and the check's output, and the note stops being delivered. In vectr this could be one more event kind that retires a note the way supersession does, with its own badge.
A death is wrong if the condition passed for the wrong reason, or if the debt came back, as when a refactor makes the test flaky again. Both need the edge Reinstatement Is the Missing Primitive in Agent Memory argues for, undoing a terminal transition without rewriting history. vectr has it already. vectr_reinstate reverses revocation, expiry and supersession, and would reverse payment the same way. For some weeks after a death, a cheap file condition can also be re-checked at session start, so a regression revives the debt without anyone remembering it.
When to evaluate
Checking every owed debt on every prompt would put a test run on every turn. Lazy evaluation bounds that: on touch, only the debts anchored to that file; at turn close, only the debts delivered and written in that turn; at session start, only file predicates. The anchor hash vectr already stores is a cache key for file predicates, since an unchanged anchor gives an unchanged answer. A command condition can depend on other files, so its cached answer is a hint.
A Memory Rule Never Blocks: Its Fire Count Says Where It Belongs
A rule warns at its trigger and goes no further, whatever its count. What the count still says is where the rule should live. JhouCode, describing a hook setup in a Claude Code feature-request thread, puts it this way: "Every firing is counted, and the count decides where the memory goes."
- Fires in most sessions. The rule is on the path of nearly all work, and the trigger only delays it. In JhouCode's words, "a memory that fires every week is only cold in name"; "A method memory, one that holds on any path, should not go to a trigger: it belongs with what always loads." In vectr that means a directive.
- Never fires over many sessions. Either the trigger is wrong or the rule is useless, or as the same comment has it, "a memory that never fires shows that the pattern is wrong or that it is not useful."
- Fires and keeps being violated. When the violation is a write to the anchor, as with the generated config, the rule is a candidate for a check. When a Memory Should Become a Check works through that trade. A check does not need to be believed, and a rule that is always enforced can never be tested again.
That piece proposes a middle rung, a note that carries a verify command. A rule's verify command and a debt's payment condition look alike and mean opposite things. A passing verify command says the rule still holds, so keep delivering it; a passing payment condition says the debt is gone, so stop. Whether a note has a check attached says nothing about which it is, so the lifecycle has to be stored.
Pick a note and a lifecycle to see what eight sessions of work on the note's file leave it as. Under either single lifecycle one of the two notes ends in the wrong state; the split lifecycle with a checked condition ends both correctly.
The scenario is fixed. The agent obeys the rule in all eight sessions. For the debt, it edits the test without fixing it in sessions 1-3, switches it to frozen_clock in session 4, and edits it again in sessions 5-8. The threshold of 3 is hipocampo's TETO_D3.
Limits of Payment Conditions, and the Tests They Need
A condition can pass for the wrong reason
"tests/test_retry.py contains frozen_clock" holds as soon as someone imports the fixture, whether or not the test still sleeps on the wall clock. That is the SATD finding one level down. The condition is a marker too, better than a comment and still satisfiable without payment. Conditions that test behaviour (the test passes 20 runs in a row) are harder to fool than conditions that test text, and evidence recorded at death lets a wrong death be found and reversed.
Branches, and files the check cannot see
A condition is evaluated against the working tree the agent is in. A debt paid on a feature branch is still owed on main until the branch merges, so the death records its commit and a session on another branch re-checks. A condition can also only see local files. JhouCode's triggers match shell command text as well as file paths, and the 12 October comment gives the reason: "A file edited with ssh host vim file.cpp never passes through a local Read". A trigger can fire on that command. A local file predicate cannot tell whether the remote file was fixed. A debt on a remote file keeps declared payment.
The tests that define the design
Four behaviours define the lifecycle, each a unit test independent of how notes are delivered:
def test_debt_whose_condition_holds_is_not_delivered(store, ws):
note = store.debt("test_retry.py is flaky", anchor="tests/test_retry.py",
condition=file_contains("tests/test_retry.py", "frozen_clock"))
ws.write("tests/test_retry.py", "def test_backoff(frozen_clock): ...")
assert on_touch(note, "tests/test_retry.py", ws) is None
assert note.state == "paid" and note.death.evidence
def test_debt_whose_condition_fails_is_delivered_and_its_miss_counted(store, ws):
note = store.debt("test_retry.py is flaky", anchor="tests/test_retry.py",
condition=file_contains("tests/test_retry.py", "frozen_clock"))
ws.write("tests/test_retry.py", "def test_backoff(): time.sleep(1)")
assert on_touch(note, "tests/test_retry.py", ws).level == "warn"
on_turn_close([note], written_paths={"tests/test_retry.py"}, ws=ws)
assert note.misses == 1 and note.state == "owed"
def test_rule_is_never_escalated(store, ws):
rule = store.rule("run make client after editing api/schema.py", anchor="api/schema.py")
for _ in range(50):
assert on_touch(rule, "api/schema.py", ws).level == "warn"
on_turn_close([rule], written_paths={"api/schema.py"}, ws=ws)
assert rule.fires == 50
def test_unknown_lifecycle_defaults_to_rule(store):
note = store.load({"content": "x", "anchors": [["a.py", None]], "lifecycle": "someday"})
assert note.lifecycle == "rule"
Three more belong beside them. One rejects, at write time, a debt whose condition already holds; one counts a timed-out condition as not paid; one checks that a reinstated death returns the debt to delivery with its miss count intact.
Every Agent Memory Note Should Know How It Ends
Back to the two notes. "config/app.yaml is generated: edit the template" should warn on every touch for as long as the file is generated, never block an agent that obeys it, and let its fire count decide whether it belongs behind a trigger or in what always loads. "test_retry.py is flaky until it uses frozen_clock" should get louder each session that edits the test and leaves it flaky, stop the first time the fixture is in the file, and keep a record of why it stopped.
None of the endings in hipocampo or vectr produces that second behaviour. Each watches something next to payment, such as the note's age, its last delivery, an edit to the file or somebody's say-so. The author of the debt knows what would settle it at the moment of writing, and that knowledge is usually lost a minute later. hipocampo keeps the two kinds apart and takes payment on declaration. vectr keeps them under one kind and ends either only when somebody calls a tool.
Many debts will never have an honest predicate, and for those, declared payment plus an escalation ladder is as good as it gets. For the rest, I would start with file predicates. They run nothing, the anchor hash makes them cacheable, and the tests for them fit on one screen. Command conditions, regression re-checks and branch scoping can wait until there is data on how often authors write a condition that passes for the wrong reason.
Sources
- hipocampo by JhouCode (MIT), at commit
b305c8c(12 October 2026): scripts/gatilho.py, lines 1-33, line 44, line 104, lines 206-220, lines 254-274, lines 332-375 and lines 378-393. - hipocampo at commit
b305c8c: docs/gatilhos/backlog.md, lines 1-33 and docs/gatilhos/memoria.md, lines 16-18. - JhouCode, comments on anthropics/claude-code#78795, 7 October 2026 and 12 October 2026.
- anthropics/claude-code issue #78795, opened 18 July 2026.
- vectr at commit
726e798: agent/working_context_store/_types.py, lines 31-34; agent/templates/claude_md.md, line 37, 51-52, 54 and 64. - vectr at commit
726e798: agent/trigger_engine.py, lines 213-224, 297-299, 494-499, 550-564 and 615-625; agent/hook_cli.py, lines 446-454. - vectr at commit
726e798: README.md, line 413; CHANGELOG.md, lines 805-810; agent/proactive/request_window.py, lines 92-96 and 153-159; agent/proactive/gate.py, lines 317-341 and 460-492; agent/config.yaml, lines 2521-2523 and 2533. - vectr at commit
726e798: agent/working_context_store/_store.py, lines 3736-3742, 3775-3784, 3999-4005 and 4216-4225; app/models.py, lines 413-420; CHANGELOG.md, lines 161-169; integrations/mcp_server/_schemas.py, lines 862-880. - vectr at commit
726e798: agent/config.yaml, lines 1213-1220 and 1235-1245; app/service.py, lines 772-781. - E. da S. Maldonado, R. Abdalkareem, E. Shihab and A. Serebrenik, An Empirical Study on the Removal of Self-Admitted Technical Debt, ICSME 2017.
- F. Zampetti, A. Serebrenik and M. Di Penta, Was Self-Admitted Technical Debt Removal a Real Removal? An In-Depth Perspective, MSR 2018.
- A. Sehwag, H. Sah and N. C. Albanese, a guide to designing memory lifecycle policies, AWS Machine Learning Blog, 4 September 2026.