Skip to content

feat: hold the prompt hook under the host's cap and split the shell rules - #1448

Merged
REPPL merged 17 commits into
mainfrom
context-cost
Nov 7, 2026
Merged

REPPL merged 17 commits into
mainfrom
context-cost

Conversation

@REPPL

@REPPL REPPL commented Nov 7, 2026 •

Copy link
Copy Markdown
Collaborator

Holds the prompt hook's output under the host's 10,000-character cap, and sends the shell rules only where they can change what an agent does.

Above that cap the host saves the hook's output to a file and shows the agent a short preview, so most of what abcd sends on a busy prompt never reaches the agent. Measured live on the released binary: 38,582 bytes written, 1,543 shown. On this branch the same kind of prompt wrote 8,761 bytes, and all of them were kept.

What changes

  • The prompt hook has one budget. The status and away blocks are read first. The rules and memory notes share what is left, and the notes keep a floor. Note room that goes unused returns to the rules.
  • A domain that does not fit shrinks instead of being cut. It goes as its first rule and the command for the rest, or the command alone. With no room for that, it waits a turn.
  • The shell rules split by what the guard does. Ahead of time, the agent gets a line about the guard and the rules that only warn. What the guard refuses, including a delete it cannot prove safe, reaches the agent at the refusal. abcd rules SHELL lists every rule. A repository's own rewording of a delete rule stays in the rules it sends ahead.
  • With the guard off, the hook says so. It sends one line saying nothing refuses or warns, the command for the list, and no hazard text.
  • SessionStart, which already kept under the cap, now reads the same constant as the prompt hook.
  • The old whole-output injector and renderer, which no production code calls any more, move into the rules package's test helpers.

What to know before relying on this

  • No reservation was taken: a build pushes one, and this work was to push nothing until it was finished.
  • The intent audit found 3 criteria met, 5 met with concerns and none unmet. It read the branch at d287ede. The listing heading it flagged was fixed afterwards in 12994e1, and that fix was reviewed but not audited again.
  • Criterion ac-5 was reworded after the first audit, under the person's delegation, with no separate sign-off.
  • Of the intent's conditions, one is untested, one survived and one was narrowed.
  • CONCURRENCY (11,406 bytes), and with a long note ATTRIBUTION and LOAD, go short on a turn until the rule-by-rule review trims them. Their first rule and the command still reach the agent.
  • The whole-output test does not exercise the status block.
  • The docs fidelity receipt is for an earlier tree. A cut on the default branch needs its own review anyway.

iss-2611070830056851 is filed here and stays open: with the person away, the stop check names one session's work to every session on the account.

Resolves: iss-2611041419354106
Delivers: itd-2611041636196213
Refs: iss-2611070830056851
Assisted-by: Claude:claude-opus-5-5

REPPL added 17 commits November 4, 2026 17:42
Both came out of the same usage review as the prompt hook's overrun and wait
behind that work. The draft records why it is parked: logs show polling inside
one wait costs more than the cache lifetime it set out to change.

Refs: itd-2611041531140641
Refs: iss-2611041527357428
Assisted-by: Claude:claude-opus-5-5
…ules

The prompt hook let rule text run to 64 KiB, but the host keeps only 10,000
characters of one hook's output and shows a 2,000 character preview of the
rest. In the seven days to 4 Nov 2026 it cut the output 475 times, and the
session ledger recorded the cut text as sent, so those rules never came back.

The rules, notes, status and away blocks now share one budget under the cap.
Domains that do not all fit take the room in steps, cheapest first: every one
gets its heading and the command that renders it, then its first rule, then
all of its rules. Only what was sent is recorded. A note that does not fit
comes back as one line, and a turn no note comes back on gives the floor kept
for notes back to the rules.

SHELL now sends one line about the guard and the rules for commands it only
warns about, since a warned command still runs. What the guard refuses reaches
the agent at the refusal, sub-agents included, and `abcd rules SHELL` lists it
all. With the guard off every rule is sent and no line claims a guard. A new
rule goes in .abcd/guard.json if a machine can catch it in a shell command and
in rules.json otherwise, with no change to either format.

Live, on the same prompt in a real host session: the released binary sent
38,582 characters, of which the host kept a preview; this one sent 8,761, all
kept.

Resolves: iss-2611041419354106
Refs: itd-2611041636196213
Assisted-by: Claude:claude-opus-5-5
A docs review of the previous commit held it for wording that claimed more
than the code does: rules back in full under a bracket that shrinks them, a
domain never sent twice when the refresh backstop can resend it, and no mention
of the delete the guard still refuses in a repository where it cannot prove the
target safe. Each passage now says what happens.

The line under a shortened SHELL also said the command renders nine rules when
it lists every hazard, so it now counts the ones the guard carries.

The guard-off criterion is narrowed to the line about the guard. Eleven registry
entries still name the guard after their opening, and rewording them belongs to
the rule-by-rule change.

Refs: itd-2611041636196213
Assisted-by: Claude:claude-opus-5-5
The zero-bytes sentence left out the away block, and the JSON object sentence
gave an away-line prompt the title's shape, with no systemMessage. The public
line about a domain that does not fit left out the form with the command alone.

The guard chapter now counts the three rules the generator adds, and says a
shortened SHELL sends the line about the guard alone. The configuration chapter
says the status and away blocks are read first and are not trimmed.

Refs: itd-2611041636196213
Assisted-by: Claude:claude-opus-5-5
The status block shows ten lines and a count between its heading and closing
lines, not ten lines in all. A full turn can leave SHELL with the command alone,
and a domain with no room even for that waits a turn.

Refs: itd-2611041636196213
Assisted-by: Claude:claude-opus-5-5
Delivers: itd-2611041636196213
Assisted-by: Claude:claude-opus-5-5
The audit of the shipped intent found four gaps, each fixed here.

A delete entry sits in the warn tier, but in a repository the guard refuses it
unless it proves the target safe, so the five of them were sent ahead of time as
warnings about commands that mostly never run. They now count as refused and are
read at the refusal, which takes what SHELL sends from 4,322 bytes to 1,419.

A short note cost the rules the whole 2,500 bytes kept for notes, so a domain
that fit beside it went short for the rest of the session. The rules are now
rendered within what the notes really took.

With the guard off the rules cannot all fit one turn, and the one that did was
whichever sorted first. The domain now opens with a line saying the guard is off,
and the docs stop saying every rule is sent.

The session-start hook takes the host's cap from the one constant.

Refs: itd-2611041636196213
Assisted-by: Claude:claude-opus-5-5
A refused delete shows the proof's reason and not the entry's words, so a
repository's rewording of a delete entry reached no agent once those entries
moved to the guard's list. A reworded one now goes ahead of time.

The docs said a delete warns outside a repository, which no front door does: it
warns only once its target is proven safe. The stderr count of bytes left now
takes the notes off too.

Refs: itd-2611041636196213
Assisted-by: Claude:claude-opus-5-5
A refused delete shows the proof's reason and a proven one the entry's words, so
the heading over the guard's list now says the command answers when it is judged.

Refs: itd-2611041636196213
Assisted-by: Claude:claude-opus-5-5
The audit read the delivery through d287ede: three criteria met, five met with
concerns, none unmet. It named two stale passages in the closed spec, fixed here,
and no test running the prompt hook with the guard off, added here.

Refs: itd-2611041636196213
Assisted-by: Claude:claude-opus-5-5
The calibration note conflicted: main graded the section above and added its own
after it, and this branch added one too. Main's grade and section stay, and this
branch's section follows them, since it was filed later.

Refs: itd-2611041636196213
Assisted-by: Claude:claude-opus-5-5
Main changed how the status read is called, and this branch reads status before
the rules: the call stays there, on the new arguments. The rules text takes main's
load-gate sentence and this branch's SHELL sentence, shortened with the prompt
sentence to keep AGENTS.md under its size limit. The calibration note keeps both
sections, in date order.

Refs: itd-2611041636196213
Assisted-by: Claude:claude-opus-5-5
Found while a peer held the pull request the check kept naming.

Refs: iss-2611070830056851
Assisted-by: Claude:claude-opus-5-5
The draft and the lab landed first in their own change. The draft takes main's copy,
less its forward-looking marker, because the id it names resolves on this branch.

Refs: itd-2611041636196213
Refs: itd-2611041531140641
Assisted-by: Claude:claude-opus-5-5
The hook now calls InjectWithin and the listing RenderListing, so nothing in
production calls Inject or Render, which the exported-reach audit main brought in
refuses. Both move to a test file, and the one test elsewhere calls InjectWithin.

Refs: itd-2611041636196213
Assisted-by: Claude:claude-opus-5-5
Clean merge; no conflicts.

Refs: itd-2611041636196213
Assisted-by: Claude:claude-opus-5-5
Clean merge. Main's one overlap is the precheck line in AGENTS.md, outside
the managed block.

Refs: itd-2611041636196213
Assisted-by: Claude:claude-opus-5-5
@REPPL
REPPL enabled auto-merge November 7, 2026 17:33
@REPPL
REPPL added this pull request to the merge queue Nov 7, 2026
Merged via the queue into main with commit e4da1db Nov 7, 2026
16 checks passed
@REPPL
REPPL deleted the context-cost branch November 7, 2026 19:04
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant