Repository navigation
design: PRs through a std/github tool, not gh or /pr - #300
Merged
Merged
Conversation
Rewrite agent-github.md's PRs section. A PR reaches GitHub in two halves
and neither checks anything out: publish_source pushes the commit from
the server's bare store, and everything else (opening a PR, retargeting
its base, linking a stack) is metadata, sent to the GitHub API by a new
inline llm-step tool, github(method, path, body?).
- Inline, not a std/github worker running gh: a worker result is
memoized by its ArgTree, the github-token secret's reader already
names std/llm-step, and gh adds nothing the API lacks. gh stack link
with PR numbers is POST /repos/{owner}/{repo}/stacks.
- Writes (anything but GET) are pinned in a tool.start before sending.
Only the attempt that appended the pin sends; one that finds the call
started and unfinished completes it as uncertain, never resends.
- The tool reaches api.github.com only and follows no redirects. Paths
are unrestricted, so the token's scope is the boundary.
- The per-layer PR recipe for a squashed stack, publish_source refusing
a commit with a .caos entry, and what removing /pr takes away.
The "Retrying GitHub writes" subsection is folded into "Writes", and
"Merges" becomes its own section. stacks.md's Publishing gains a third
step pointing at "PRs for a stack" in place of the TODO, and its
"Not built" section goes: linking is now designed, and the reasoning
about the rest of gh-stack moved into agent-github.md.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CZGkTta5NYxhXcLPZwH3q1
This was referenced Oct 5, 2026
nishu-builder
commented
Oct 5, 2026
Review on #300: the GitHub caller should follow the general pattern, a std tool run by path, not a built-in inline in llm-step. - std/github: run with run_tool(path="caos-std/github"), described by tool_help. Arguments method, path, body and at. The token reaches it through a second reader: line naming std/github. - at: a run is memoized by its ArgTree, so each call carries a value of its own (salt is reserved for the interpreter). Repeating every argument returns the stored result; a write is therefore sent once per stored result, at least once if its run dies mid-flight. - Not gh: one line, its stack commands need local branches, so a repository would be materialized for every call. - No publication check. Resolving a conflict clears its ledger entry and saving removes the emptied ledger, so a ledger survives only while a conflict is unresolved, which is the same mistake as publishing code that does not build. The Writes and Publication checks sections go; the tool.start pin was the inline design's. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01CZGkTta5NYxhXcLPZwH3q1
nishu-builder
pushed a commit
that referenced
this pull request
Oct 5, 2026
Review on #300: follow the general pattern. std/github is a tool like any other, run with run_tool(path="caos-std/github") and described by tool_help; llm-step's inline github tool and its tool.start pin go. - worker.go, on std/go (whose image carries the CA bundle): one call to api.github.com per run. Arguments method, path, body and at. The result is the status line and the body, cut at 100 kB on a character boundary; a response of any status is a result, and only a request with no response fails the run (for a write, saying it may still have arrived). Redirects are not followed and the host is fixed, so the token goes nowhere else. Arguments are checked before anything is sent: the method, an API path (a full api.github.com URL is accepted), no body on a GET, a body that is JSON. - at is required: the tool has no @in, so its ArgTree is its arguments, and a call repeating all of them returns the stored result (salt is reserved for the interpreter). - The token is /secret/github-token, granted by a second reader: line naming std/github. Also reverted from the previous commit: publish_source's .caos refusal, the SPEC.md registry entry, and agent-publish.md's note. publish_source's help points at caos-std/github; the agent guide opens PRs and links a stack with it, and no longer suggests /pr. Checked locally against a stand-in server, the worker built from this file with the API base, /cas/args and /secret paths read from the environment, and a fake caos: a POST sent once with its body verbatim and Accept, API version, Bearer and JSON content-type headers; a GET with no token sends no Authorization and a 401 gets the no-token hint; a 302 is reported and not followed; a 120 kB body is cut at 99,999 bytes, valid UTF-8; a bodiless PUT sends Content-Length 0; bad method, missing at, a GET body, a relative or spaced path and non-JSON bodies are refused before sending; a dead server fails the run, with the may-have- arrived advice for a write. go build, go vet and gofmt are clean, and llm-step's 46 tests pass. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01CZGkTta5NYxhXcLPZwH3q1
nishu-builder
pushed a commit
that referenced
this pull request
Oct 5, 2026
Follows the review on #300, now merged in: the GitHub caller is the std tool caos-std/github, and publication has no conflict check. SPEC.md, chat.md and TUI.md name the tool, and SPEC.md and TUI.md no longer say a .caos entry blocks publication: resolving a conflict clears its entry and saving removes the emptied ledger, so one left in a published commit is an unresolved conflict, like code that does not build. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01CZGkTta5NYxhXcLPZwH3q1
The PRs section stated that nothing is checked out four times, described at in a table, a section and the stack recipe, said twice that a failed write may have arrived, and restated the tool's help in an argument table and stacks.md's republish note. Each is now said once: half the length, same design. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01CZGkTta5NYxhXcLPZwH3q1
The secret file example under Importing now carries both reader lines, llm-step's and std/github's, and the PRs section says plainly that the tool uses the same github-token secret imports do, so no new secret is made: its file gains one reader line. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01CZGkTta5NYxhXcLPZwH3q1
nishu-builder
added this pull request to stack #306
October 5, 2026 07:30
nishu-builder
added a commit
that referenced
this pull request
Oct 5, 2026
* llm-step: a github tool for PRs, and publish_source refuses .caos github(method, path, body?) makes one call to api.github.com, inline in the step, with the github-token secret llm-step is already granted for imports (design/agent-github.md, "PRs"). With publish_source pushing the commits, it is everything else a PR needs: find a branch's open PR, open one, change its base, link a stack. Nothing is checked out. - A GET runs, and a retry runs it again. Any other method is a write, pinned in a tool.start (github.json: the exact request) before it is sent. Only the attempt whose tool.start was appended sends it; an attempt that finds the call started and unfinished completes it as not confirmed and never sends it again. The pin carries a per-attempt nonce, since two attempts minting the same commit would each see their own append land and both send. - The body is pinned as the text sent, not as JSON: canonical JSON has no negative or fractional numbers, and a body a model writes must not be able to fail the pin. - Only api.github.com is reached, and redirects are not followed, so the token goes nowhere else. Paths are unrestricted; the token's scope is the boundary. publish_source now refuses a commit whose root tree has a .caos entry, such as an uncleared .caos/conflicts ledger. It reads the commit and its root tree, nothing else. /pr made this check; a squash carries a ledger into its commit, so a squashed layer needs it too. The agent guide opens PRs with the github tool, including the per-layer PRs and stack link for a squashed stack, and no longer suggests /pr, which the next change removes. SPEC.md lists the tool among the registered built-ins. Tests, run with cargo over llm-step and its spliced crates: request checks, rendering and truncation; a write pinned then sent once, with a lost acknowledgement on the pin; a write another attempt pinned, before this one or racing it, never sent again; a GET that is not pinned and does not follow a 302; publish_source's .caos check. A local HTTP server stands in for api.github.com. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01CZGkTta5NYxhXcLPZwH3q1 * std/github: the GitHub caller as a std tool, not built into llm-step Review on #300: follow the general pattern. std/github is a tool like any other, run with run_tool(path="caos-std/github") and described by tool_help; llm-step's inline github tool and its tool.start pin go. - worker.go, on std/go (whose image carries the CA bundle): one call to api.github.com per run. Arguments method, path, body and at. The result is the status line and the body, cut at 100 kB on a character boundary; a response of any status is a result, and only a request with no response fails the run (for a write, saying it may still have arrived). Redirects are not followed and the host is fixed, so the token goes nowhere else. Arguments are checked before anything is sent: the method, an API path (a full api.github.com URL is accepted), no body on a GET, a body that is JSON. - at is required: the tool has no @in, so its ArgTree is its arguments, and a call repeating all of them returns the stored result (salt is reserved for the interpreter). - The token is /secret/github-token, granted by a second reader: line naming std/github. Also reverted from the previous commit: publish_source's .caos refusal, the SPEC.md registry entry, and agent-publish.md's note. publish_source's help points at caos-std/github; the agent guide opens PRs and links a stack with it, and no longer suggests /pr. Checked locally against a stand-in server, the worker built from this file with the API base, /cas/args and /secret paths read from the environment, and a fake caos: a POST sent once with its body verbatim and Accept, API version, Bearer and JSON content-type headers; a GET with no token sends no Authorization and a 401 gets the no-token hint; a 302 is reported and not followed; a 120 kB body is cut at 99,999 bytes, valid UTF-8; a bodiless PUT sends Content-Length 0; bad method, missing at, a GET body, a relative or spaced path and non-JSON bodies are refused before sending; a dead server fails the run, with the may-have- arrived advice for a write. go build, go vet and gofmt are clean, and llm-step's 46 tests pass. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01CZGkTta5NYxhXcLPZwH3q1 * std/github: take the call id from the harness instead of `at` std/github's results are kept by their arguments, so each call needs a value of its own among them. That was `at`, a parameter the model filled in; it read as a timestamp, and models invented dates for it. A reused value also silently returned an earlier call's result. A new help tag, `@call`, has llm-step bind the tool call's id as `call`. The id is unique to the call and the same when a call is recovered, so a retry still gets the stored result and a new call gets a fresh run. The model no longer sees the parameter. `call` is reserved, like `in` and `wc`. A caller outside llm-step passes --call itself. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude <noreply@anthropic.com>
nishu-builder
added a commit
that referenced
this pull request
Oct 5, 2026
* caos-cli: remove /pr, /publish-branch and the client publisher
The agent publishes now: publish_source pushes the commit from the
server's store and the github tool opens or updates the PR
(design/agent-github.md, "PRs"). The client's own path to the same end
goes, and with it the client's need for gh, a host git push, and a
local copy of the history it publishes.
Removed:
- TUI: the /pr and /publish-branch commands, the preview modal and its
key and mouse handling, the publishing state and its status, sidebar
and footer rendering, and the PublicationPlanned, Published and
PublicationBaseImported messages (bin/tui/publication.rs).
- Library: src/publication.rs (gh pr create/edit), the publication
half of source_trees.rs (preview, provenance inference, base import,
default_branch, branch_snapshot), the PR half of host_git.rs, and in
lib.rs the client push (publish_source_tree_branch and friends),
reject_publish_caos, publication_diagnostic, PublishedBranch, and
append_system_notice, which only the publisher called.
- Their tests.
Kept: publication records stay readable. The agent's publish_source
still writes them, and conversation_load still summarizes them; a new
test appends one the way llm-step does and loads it back. Two escape
key tests lose their publishing cases and keep the running ones.
Docs: chat.md's "Publishing with /pr" becomes a short "Publishing"
pointing at the agent's tools; TUI.md, SPEC.md ("Publication"),
README.md and agent-harness.md drop the commands.
cargo test -p caos-cli: 39/39 lib, 148/150 bin. The two failures,
plain_commit_fork_failure_never_becomes_a_markerless_conversation and
checkout_import_completes_partial_history_and_keeps_local_edits, fail
identically without this change on this machine's git 2.43 (a promisor
lazy fetch, and a git error message). cargo clippy -p caos-cli
--all-targets -- -D warnings and cargo fmt --all --check are clean.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CZGkTta5NYxhXcLPZwH3q1
* docs: caos-std/github opens PRs, and nothing refuses .caos at publish
Follows the review on #300, now merged in: the GitHub caller is the std
tool caos-std/github, and publication has no conflict check. SPEC.md,
chat.md and TUI.md name the tool, and SPEC.md and TUI.md no longer say
a .caos entry blocks publication: resolving a conflict clears its entry
and saving removes the emptied ledger, so one left in a published commit
is an unresolved conflict, like code that does not build.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CZGkTta5NYxhXcLPZwH3q1
---------
Co-authored-by: Claude <noreply@anthropic.com>
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.
First of three PRs that replace the TUI's
/prwith agent-side publishing: #300 (this, the design) → #301 (std/github) → #302 (removes/pr). This replaces stack #261, which is closed.The PRs section of
design/agent-github.md, rewritten:publish_sourcealready pushes the branch from the server's store.std/github, a std tool, sends the rest to the GitHub API. Neither checks anything out.at. Runs are memoized by their arguments, so each call carries anat. A repeated call returns the stored result; only a run that died mid-flight sends a write twice.github-tokensecret, granted by a secondreader:line namingstd/github. Its scope is the boundary./pr, including its conflict checks, which nothing replaces.design/stacks.mdpoints its publishing steps at the recipe.🤖 Generated with Claude Code
https://claude.ai/code/session_01CZGkTta5NYxhXcLPZwH3q1