Repository navigation
Releases: fredericrous/amont-agent
Release list
v2.31.0
Added
unbounded-background-push: a push sent to the background needs a
deadline.git pushruns the pre-push gate inside it — a test suite, a
lint pass — and withrun_in_backgroundno clock ends it and nothing says
it is still going: on 2026-10-08 a push seeding a fork held a session for
forty minutes before anyone asked (#86). The rule advises on a background
git pushwhose output goes to a file (> push.log 2>&1, the shape a
backgrounded push takes) and notimeoutwrapper, and points attimeout <s> git push …, which push-preview and implementation-review read through, plus
amont rehearse --waitso the push itself skips the suite. A foreground
push (the tool's own timeout bounds it) and a dry run stay silent.
What's Changed
- feat(rules): bound a background git push; 2.31.0 by @fredericrous in #88
Full Changelog: v2.30.2...v2.31.0
v2.30.2
Fixed
- Pushing commits some remote already has needs no preview and no
implementation review. Seeding a fork (git remote rename origin upstream, add the fork asorigin, push a branch) publishes nothing this
session wrote: every commit is already onupstream/*.push-preview
listed the files with--not --remotes=<target remote>, which excludes
nothing on an empty fork, so upstream's whole history read as an
unapproved interface change;implementation-reviewfound no default
branch on the fork and asked for a review of it. Both guards now stop at
"nothing new to any remote" (git rev-list <src> --not --remotesis
empty); a commit new to every remote is still judged exactly as before.
The same mistake in amont's pre-push gate was amont#301 (1.47.2).
What's Changed
- fix(push): commits on a remote need no gate; release 2.30.2 by @fredericrous in #87
Full Changelog: v2.30.1...v2.30.2
v2.30.1
Fixed
push-preview: an unedited template placeholder is not evidence. The
plan templates carryevidence: <why …>under## Preview. A plan
approved with that line left as it was declared evidence and passed the
push with no question. A reason that starts with<now declares nothing,
and the push asks as usual.
What's Changed
- fix(preview): a placeholder is not evidence (2.30.1) by @fredericrous in #85
Full Changelog: v2.30.0...v2.30.1
v2.30.0
Approve only what needs judging (ADR-0028, which replaces ADR-0023).
Existing installs must re-run amont-agent install --write: the
evidence gate needs the new PostToolUse hook on ExitPlanMode.
Added
push-preview: a plan can declare the preview's evidence. When the
plan a branch landed was approved throughExitPlanModeand its body has
a## Previewsection whose first line isevidence: <reason>, a UI push
passes with no question (rulework.preview-unless-planned-evidence).- The approval record. A new
PostToolUsehook onExitPlanMode
writes the approved plan's canonical body sha to
~/.claude/amont-agent/plan-approved/<sha>, hashed from
planFilePathwhen the hook runs. Only the approve shape counts
(tool_responsean object carryingplan). - The check. The first plan the branch adds under
docs/plans/since
the merge base with the default branch, read at the commit that added
it, must have an approved sha and the declaration. A picked mockup, a
pointer plan, a plan already onmain, a section added later and a
missing base ref are held as before. - Audit. Every pass is journalled
evidence, with the plan, the
commit and the sha; every recordplan-approved.
- The approval record. A new
preview registerprintsquestion_prefix:[preview <id>] <label>,
what the marked question starts with, verbatim. A refusal to bind quotes
it.implementation-reviewcounts a resumed review. A reviewer resumed
withSendMessageon a new block is a review of that tree: the message's
tois a reviewer'sagentId, its result'sresumedAgentIdmatches, and
the round's structured notification names that SendMessage and agent.
The plan-review panel still counts fresh launches alone.
Changed
- A marked question approves by id.
Approveon a question whose
[preview …]marker lists a pending registration approves it; the
repo@sha7label is no longer required (the id starts with the sha7).
The "bound NOTHING" answer and itsunlistedjournal line are gone. - A chained register binds.
preview registeronly has to be the last
clause of its line, joined by&∨; the JSON is read from the last
non-empty line of stdout. APreToolUsestamp
(previews/registers/<tool_use_id>, swept after a day) and an id, page
and mtime check keep a line an earlier clause printed from passing as
the register's. No stamp: not bound. A register that is followed,
piped, redirected or substituted stays unbound. - The vendored decisions pack carries ADR-0028.
Fixed
- The person was asked twice for one preview (2026-10-08): a question
carrying the id but no label bound nothing.
What's Changed
- feat: approve only what needs judging (2.30.0) by @fredericrous in #84
Full Changelog: v2.29.1...v2.30.0
v2.29.1
Fixed
push-preview: an unreadable push is held as unreadable. Under
denya push whose shape cannot be read is still held, but it no longer
says "no approved preview covers" or gives the preview steps. It names
the shape and its own remedy: push the ref by name, in its own command.
The most common case isgit tag v1 && git push origin v1, judged
before the tag exists; that shape now says so. A push of an existing tag
needs no preview, as before. The missing-directory hold no longer gets
the preview steps either (Confirmed::YesSayinggainsremedy).preview registeron the default branch itself. A commit that is
its own merge base (taggingmain) no longer fails with
`git diff <c>..<c>` failed; an empty range is no screen.
What's Changed
- fix(preview): unreadable holds, register on main by @fredericrous in #82
- chore: release 2.29.1 by @fredericrous in #83
Full Changelog: v2.29.0...v2.29.1
v2.29.0
Added
-
publish-without-skill: a release or a merge needs its skill. A new
rule, shipped asadvise(ceilingdeny). It fires on three commands:- a
git pushthat publishes av*tag (--tagsand--mirrorincluded); gh pr merge;- an HTTP client sent to
/pulls/<n>/merge.
The rule looks for a call of the
tag-releaseormerge-when-greenskill
(a Skill call, or the person typing/tag-release) in this turn or in the
human turn before it. A skill called within that window passes silently.- Reading the transcript. It is read backwards from its end, and only
as far as the second human prompt. - Subagents. A subagent's own transcript (
agent_transcript_path) is
read too. - When it cannot tell, it never refuses. That covers a missing,
unreadable or truncated transcript, a turn longer than 16 MB, or a skill
that is not installed. - To refuse:
git config --global amont.agent.publish-without-skill.stance deny. - Measured on 2026-10-07: 8.4–28.3 uncovered publishes per 1000 Bash
calls by week, falling. Count withtools/skill-rate.py.
- a
Changed
release-tag-pushalso matches+refs/tags/v…and--mirror. It now
shares its matcher withpublish-without-skill.--follow-tagsstays
unmatched.
What's Changed
- feat(rules): publish-without-skill gate by @fredericrous in #80
- chore: release 2.29.0 by @fredericrous in #81
Full Changelog: v2.28.0...v2.29.0
v2.28.0
Added
plan-phases-open: an agent no longer stops between plan phases. A
newStophook, shipped asdeny: when the agent ends its turn while the
activeplan its branch carries (docs/plans/, changed since the
merge-base with the remote default branch) still has an open phase that
is not a🧑 decision:, the turn continues with that phase. It lets the
turn end in plan mode, while background tasks run, on a last-message line
starting withWAITING: <reason>, and after three continuations on one
phase, when it tells the person instead. Existing installs must re-run
amont-agent install --writeto add theStopentry;doctornow
names the events an install lacks.
What's Changed
- feat(rules): plan-phases-open — keep an agent going between plan phases by @fredericrous in #78
- chore: release 2.28.0 by @fredericrous in #79
Full Changelog: v2.27.1...v2.28.0
v2.27.1
Fixed
- A delete-only push is not held under deny (#66).
git push origin --delete <branch>…,-d(also inside a cluster such as-ud), and a
push whose every refspec is:<ref>publish nothing, sopush-preview
andimplementation-reviewnow pass them (a delete publishes nothing
anddelete-onlyin the journal) instead of holding them as unreadable.
A push that deletes and publishes at once,--deletewith asrc:dst
refspec, and--pruneare still unreadable, and still held under deny. - A push from a removed session directory is judged, not waved
through (#67). Every confirmed rule used to decline as soon as the
session's cwd was gone, socd /abs/repo && git push …from a session
left in a torn-down worktree passed every push gate. The test is now
whether the matched clause's own directory exists,cds followed. When
it does not,push-previewandimplementation-reviewhold the push
under deny, because the shell then runs somewhere the hook cannot name
(Claude Code resets it to the project root). Other rules still decline. - A firing hook call no longer spawns git once per key (#70). Every
stance lookup rangit configtwice (--global, then--system), so a
call firing one rule spawned six git processes and a Bash command firing
several spawned more. Each scope'samont.agent.*keys are now read once
per process with--get-regexp, both scopes in parallel. A boolean that
is actually set is still normalised by git (--type=bool), and the scope
rule is unchanged: only--globaland--system, with their includes.
Measured on a loaded macOS machine, release build, 100–200 runs each: a
firing Read went from 111 to 38 ms p50, and a Bash command firing several
rules from 398 to 38 ms p50 (p99 788 → 69 ms). The silent path is
unchanged (~10 ms). One git spawn costs ~30 ms here under load, so the
issue's 30 ms budget is not met on this machine.
What's Changed
- fix: delete-only pushes, removed cwd, config spawns by @fredericrous in #75
- chore: release 2.27.1 by @fredericrous in #77
Full Changelog: v2.27.0...v2.27.1
v2.27.0
Added
amont-agent rules --json. One array, one object per rule and per
assertion, withid,kind,default_stance(what ships),stance
(what is in force here),max_stance,per_1000andmeasured. The
keys are an interface: the homebrew tap reads them.rulesnow refuses
any other argument (exit 2); until now it ignored them, sorules --json
printed the text table.
Fixed
- The brew caveat names every rule that refuses by default. It said
onlypipe-to-tailrefuses, false sinceplan-review-panelshipped at
deny in 2.22.0. The release now writes the list from the published
binary'srules --json(scripts/bump-tap.py), and from 2.27.0 the
formula'sbrew testchecks it against the brewed binary.
What's Changed
- docs(plan): lint-suppression-added, done by @fredericrous in #73
- feat(rules): rules --json; tap caveat generated from it by @fredericrous in #74
- chore: release 2.27.0 by @fredericrous in #76
Full Changelog: v2.26.0...v2.27.0
v2.26.0
Added
lint-suppression-added: an edit that adds a lint suppression is
advised. On an Edit, MultiEdit or Write the hook rebuilds the file
before and after (a bounded read that never opens a FIFO) and compares
suppression markers, not lines:# type: ignore,# noqa,
# pyright:headers,eslint-disable,@ts-ignore,#[allow]/#[expect],
//nolint, and a lint configuration made looser (tsconfig, eslint,
pyright, ruff, Cargo[lints],.golangci.yml). Editing a line that
keeps its suppression, or moving one, is silent. The advice points at
general.no-disabled-safety; the journal records the marker kind and
whether the file was read whole or only the fragments were seen.
Shipsadvise, ceilingdeny.tools/suppression-rate.pyprints the
weekly rate from transcripts.
What's Changed
- feat(rules): lint-suppression-added by @fredericrous in #71
- chore: release 2.26.0 by @fredericrous in #72
Full Changelog: v2.25.0...v2.26.0