Repository navigation
Core agent principles and the one-way / two-way door rule (M9.30, M9.38); hard-lined goals retire (M9.29) - #86
Merged
Conversation
…edger Every aloop agent carries seven core principles drawn from Amazon's leadership principles, the door rule first: a two-way door (reversible) is decided and recorded, never asked; a one-way door is crossed only under the human's recorded authorization, else the agent stops with one question and a recommended option. - principles.md `## Core` + `principles show --core`, injected by session-start in an aloop project (after the resume context). - doors.json: the catalogue of one-way doors and walls; anything unlisted is two-way. - doors.py: classifies an action by program and arguments (wrappers, sh -c, redirects), reads human door.authorized/door.revoked ledger rows (standing, until, once bound to one action's sha256), records door.crossed, and runs as the PreToolUse hook (deny JSON, fails closed). A broken ledger opens nothing. While a run is live a question to the human must name a door the agent was denied. - door.authorized/revoked are human ledger events; door.denied and door.crossed are gate-owned. Ethics (M9.4): ethics.reviewed and ethics.blocked are written with M.record and the verdict reads the ledger only, so a hard line holds on a fresh checkout, a stream-only record decides nothing, and a broken ledger blocks every verdict. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012rsDo9GYzNx8tXucywZHnA
Each finding is a test that failed before its fix: - Bash is read as the shell reads it: comments, line continuations, heredoc bodies (data unless a shell or python runs them), xargs, find -exec and `echo ... | sh` are handled. - A `when` condition reads the directory the command acts on (git -C DIR, cd DIR &&); an unresolved one counts. - Settings and the ledger are matched by path suffix (~/.claude, a worktree's own copy). - Dry runs, help pages and `command -v` are two-way. - git -c core.hooksPath= is a wall; git config core.hooksPath is a one-way door. - The newest decision by time counts, and run-log revokes close the door on every branch. - A once-grant is crossed under a lock. - A broken ledger is named in the ASK and blocks authorize. - authorize refuses an agent's shell (CLAUDECODE). - The question gate is live only once a sprint's plan is approved, for the lock's session. - Slack's real send tools are one-way. - Hard ethics lines that exist only in the run log still bind. New ROADMAP items: M9.36 (authorize on the typed line, after M9.17), M9.37 (stdin to data clients), M9.38 (one shell reader with M9.9). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012rsDo9GYzNx8tXucywZHnA
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012rsDo9GYzNx8tXucywZHnA
adeelahmad
pushed a commit
that referenced
this pull request
Oct 20, 2026
…#86) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Aw6CiQcdpzdzZZXKf8WbUM
adeelahmad
pushed a commit
that referenced
this pull request
Oct 20, 2026
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Aw6CiQcdpzdzZZXKf8WbUM
adeelahmad
pushed a commit
that referenced
this pull request
Oct 20, 2026
…87 M9.28-30, #74 M9.40-42, #86 M9.50+) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Aw6CiQcdpzdzZZXKf8WbUM
adeelahmad
pushed a commit
that referenced
this pull request
Oct 20, 2026
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Aw6CiQcdpzdzZZXKf8WbUM
…branch Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012rsDo9GYzNx8tXucywZHnA
… (M9.30, M9.38) The second adversarial review of the door gate found 26 real problems; each is now a test that failed before its fix. - The gate reads Bash with the scope gate's _shellread.py (M9.38). The reader now keeps each heredoc's body (Word.body), the operator that ends a command (Cmd.end) and heredoc bodies inside $( ... ), and reads long words in linear time. Stdin (a heredoc, here-string or echo/printf/cat pipe) reaches only the command it feeds; pushd/popd, sh -c, eval and fed shells keep the directory; nesting past 8 is unreadable and a read past 8 s fails closed. - Catalogue: python is a forge only when it calls a writer; npm/pnpm/yarn -g only with an installing verb; the ledger only at docs/agents/mission/; xargs -I replaces its string; secret commands' dry runs and help are two-way; git push origin HEAD on the default branch asks; erasing the run log is a wall. - State: M.record writes the ledger row before its stream event and ledger_problems reads the stream first; a record is dated no earlier than any row; a closed sprint or a new intent ends the live run; malformed run-log lines never crash the ethics check. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012rsDo9GYzNx8tXucywZHnA
…r options The third review found that the shared reader dropped the substitutions of an array assignment (x=( $(npm publish) )), and that `time -p --` and `sudo -u root --` hid the command. Also `sh -c -e STRING`, `env -S STRING`, `exec -a NAME` and `sudo -s CMD` now find the command they run (each option set is per wrapper, so a value-taking option no longer swallows the program). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012rsDo9GYzNx8tXucywZHnA
… into the door rule branch ethics.py takes master's M.history reading (M9.24) and keeps this branch's hardening: a run-log event whose data is not an object is skipped, and a non-list words/gaps field is ignored, so a malformed line never crashes a verdict. The ethics test follows master's wording for a broken ledger and a disagreeing stream record (blocked, not asked). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012rsDo9GYzNx8tXucywZHnA
Before: a goal an ethics hard line held stayed the active goal. Every later `mission evaluate` was narrowed to it, `goal derive` refused that eval, and `goal close` refused the goal, so th 8000 e mission deadlocked. `evaluate.active_goal` now skips a goal whose ethics verdict is hard (the verdict's own rule), so the next eval covers the whole mission and derive moves past it. `goal derive` on an eval narrowed to a retired goal says to evaluate again instead of naming a close that cannot succeed. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012rsDo9GYzNx8tXucywZHnA
…erive the next gap tick hands out EVALUATE for an eval narrowed to a goal a hard line retired (evaluate now skips it), then DERIVE_GOAL, which takes the next gap. When a hard line holds every open gap, tick asks the human (BLOCKED) instead of handing out a derive that would refuse. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012rsDo9GYzNx8tXucywZHnA
…anch CHANGELOG keeps both sides. ROADMAP M9.31 now names the dsh plugin (aloop.mjs), whose PreToolUse list mirrors hooks.json by hand and so lacks `mission doors hook`. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012rsDo9GYzNx8tXucywZHnA
…M9.38)
The shell reader ends a $( … ) where bash does: here-strings, `<<` inside
$(( )), (( )), ${…} and $[…], `#` comments, case patterns' `)`, and two
heredocs on one line. close() is memoized so a deep nest stays linear, and
a nest past the recursion limit fails closed. A heredoc's delimiter is its
literal word, `]]` glued to an operator ends a test, and $((cmd)…) and
((cmd)…) fall back to a subshell as bash does.
The door gate reads a pipe into ( … ), the last stdin redirect, a python
that runs its stdin, /dev/stdin, `bash SCRIPT`, the aladdin and agentic
entry points, a ledger or run log reached through cd, a glob or
--in-place, npm -g with option values or install aliases, and a secret
value holding ` --help`. A branch created in the same command (`git switch
-c x && git push -u origin HEAD`) is not the default branch. A revoke that
only the run log has is compared with an authorization on the run log's
clock, so a ledger time pushed ahead by a fast clock cannot outrank it.
Each finding is a test: mission-doors (21 checks) and 15 new rows in
mission-scope-bash.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012rsDo9GYzNx8tXucywZHnA
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012rsDo9GYzNx8tXucywZHnA
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012rsDo9GYzNx8tXucywZHnA # Conflicts: # CHANGELOG.md # docs/ROADMAP.md # plugin/bin/_mission.py
adeelahmad
marked this pull request as ready for review
October 20, 2026 10:18
adeelahmad
pushed a commit
that referenced
this pull request
Oct 20, 2026
mission-doors.test.py (#86) made a sprint live by calling record_authority() with no grant, which emitted plan.approved for any plan. Since M0.9 plan.approved is only the human's typed approval of that sprint's plan, so the test now records it the real way (`events authority --sprint 1`, the human types the line it asks for). ROADMAP: the door gate's live_run should read `events approval` too. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01WBVFNrEg85XAnSfHQidCXN
adeelahmad
pushed a commit
that referenced
this pull request
Oct 20, 2026
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01AiLhAWTRtwbgMCDQNJUbea
adeelahmad
pushed a commit
that referenced
this pull request
Oct 20, 2026
…er and rule fixes The merge follows the #86 thread's recipe for _shellread.py (Word.body ours, Cmd keeps end plus loop/pipe, their heredoc registration, `for NAME do`), and doors.py skips the reader's compound markers and keeps a pipeline element's cd in the element. Round 4 (the verifiers of round 3): the scope gate walks every state a command may leave the shell in. A cd inside an if/case/loop body, group or function, or after && / ||, may or may not have run, so the rest is judged from each dir (a compound's own `} > f` from where it started); a loop body once per item; unquoted $VAR splits; eval and source /dev/stdin run in the calling shell; a background job's cd stays in it; nesting past 8 levels, more than 1024 walks or 50 000 judged commands blocks. find's -name tests bound a removal through -o alternatives and negations; -fprint/-fls write; wget --spider -O, npm -g --prefix, --global=false, os.environ.__setitem__/ update, xargs -i/-I{}, runuser options and `command -p export` are read. Residuals are ROADMAP M9.54. mission-scope-bash.test.py: 718 commands. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0197nSutKR1QAAqgJhFZ8fPj
adeelahmad
pushed a commit
that referenced
this pull request
Oct 20, 2026
…tifact-gate fixes Conflicts: CHANGELOG (master's lines, this track's M9.9 sub-bullet kept), ROADMAP (master's rows; this track's M9.41/M9.42; its follow-up row moves from M9.43, which master took, to M9.48). The track's new checks now get the human's typed line for an approval (grant(), and the OpenCode test types it through the UserPromptSubmit hook), and the ledger row that came through git cites the human's words, as M9.17 requires. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0197nSutKR1QAAqgJhFZ8fPj
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Requested by Adeel · project thread
Before: agents decided when to ask the human from prose alone. Nothing stopped an agent from pushing to
main, publishing, deploying or emailing on its own. Nothing stopped it from interrupting the human with a question it could have decided itself. Separately, a goal that crossed an ethics hard line deadlocked the mission loop, becauseevaluatekept narrowing to it andgoal deriverefused.After: every aloop agent carries seven core principles drawn from Amazon's Leadership Principles, with the door rule first.
ASK[door] <id>, and the agent asks one question with a recommended option.A hard-lined goal is now retired: the loop evaluates the whole mission again and derives the next gap. When a hard line holds every open gap, the loop asks the human.
How
principles.md## Coreandprinciples show --core.session-startinjects the block.doors.jsonis the catalogue; anything unlisted is two-way. Each door has a grant (standing,once,never,command), the reason it is one-way, and examples thatdoors checkproves.doors.pyreads Bash with the scope gate'splugin/bin/_shellread.py(M9.38).sh -c,eval,bash SCRIPT,find -exec,xargsand stdin (heredoc, here-string,echo|printf|cat |, a pipe into( … ), the last fd-0 redirect,/dev/stdin, a python that runs its stdin) into the command they feed.cd,pushd/popd,git -Cand$(git rev-parse --show-toplevel), and places operands and writes relative to the project or this worktree, so a ledger or run log reached throughcdor a glob is still the ledger.git switch -c x && git push -u origin HEAD) is not the default branch; after;it may be.close()ends a$( … )where bash does (here-strings,<<inside$(( )),(( )),${…},$[…],#comments,casepatterns, two heredocs on one line) and is memoized, so a deep nest stays linear; a heredoc's delimiter is its literal word;]]glued to an operator ends a test;$((cmd)…)and((cmd)…)fall back to a subshell as bash does. The scope gate gains 15 rows for these.aloop mission doors authorize|revokein the human's own terminal. An agent's shell is refused. A once-grant is bound to one action's sha256, lasts 24 h and is used up by its first crossing. A broken ledger opens nothing.M.recordwrites the ledger row before its stream event, andledger_problemsreads the stream first, so no gate sees a half-written record. A revoke only the run log has (another branch) is compared with an authorization on the run log's clock, so a ledger time a fast clock pushed ahead cannot outrank it.evaluate.active_goalskips a hard-lined goal.tickhands out EVALUATE and then DERIVE_GOAL for the next gap, or BLOCKED when every gap is held.Evidence
bad 0.mission-doors.test.py: 21 checks.mission-scope-bash.test.py: 15 new rows (12 failed on the old reader).mission-ethics.test.py: 14.mission-tick.test.py(with M9.29).mission-goal.test.py: section 11.scripts/test/*.test.pyfiles pass on master + this branch.make pycheck test-hostsexits 0,check-trackingis ok, andclaude plugin validate ./plugin --strictpasses._shellread.pyand re-applies its own changes (a trial merge of both passes scope-bash, roles and doors).🤖 Generated with Claude Code
https://claude.ai/code/session_012rsDo9GYzNx8tXucywZHnA