Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 6 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -871,8 +871,9 @@ requested unused path. Use /import for local checkouts.
### Publishing and GitHub

Ask the agent to publish a named source tree or a stack. The `publish_source` tool
pushes the selected code commit directly from the server with an expected-head
lease. The `github` tool runs GitHub CLI for PRs, comments, issues and linking
existing PR URLs into stacks. Add `reader=std/github` alongside `reader=std/llm-step`
in the `github-token` secret. See [publication and stacks](design/agent-publish.md)
for examples, credentials and retry behavior.
pushes one branch; `push_stack` pushes the branches in a registered source stack.
Both push directly from the server with expected-head leases. The `github` tool
runs GitHub CLI for PRs, comments, issues and linking existing PR URLs into stacks.
Add `reader=std/github` alongside `reader=std/llm-step`
in the `github-token` secret. See [GitHub interactions](design/agent-github.md)
for imports, branch publication, stacks, PRs, credentials and retry behavior.
4 changes: 2 additions & 2 deletions SPEC.md
Original file line number Diff line number Diff line change
Expand Up @@ -634,8 +634,8 @@ An unfinished claim is uncertain; inspect GitHub before proceeding.

PR and stack operations compose these tools. Stack boundaries remain gitlinks;
publish bottom to top and keep PR membership through GitHub’s stack API.
The TUI's /pr and /publish-branch are removed; /import remains for local paths.
See [agent publication](design/agent-publish.md) for mechanics and recovery.
Use the TUI's /import for local repositories and /checkout for local editing.
See [GitHub interactions](design/agent-github.md) for imports, publication, stacks, PRs and recovery.

## Agent stack updates

Expand Down
67 changes: 26 additions & 41 deletions design/agent-github.md
Original file line number Diff line number Diff line change
@@ -1,38 +1,31 @@
# Importing and publishing
# GitHub interactions

Imports are implemented through the server endpoint, `caos import-git`, and the agent's `import_source` tool. Publication pushes individual branches or registered stacks of branches. Stack operations
keep merge drafts outside source history.
The agent imports code, edits source gitlinks, and publishes their commits as remote branches. It uses GitHub CLI for PRs, reviews, issues and comments. The TUI handles local imports and checkouts.

## Importing
| Workflow | Design | Main tools |
| --- | --- | --- |
| Bring remote code into a conversation | [Importing remote source](agent-import.md), [server fetch and negotiation](git-import.md) | `import_source`, `caos import-git`, `POST /git/import` |
| Publish one source gitlink as a branch | [Publishing branches](agent-publish.md) | `publish_source`, `caos push-git`, `POST /git/push` |
| Update and publish related branches | [Stacks](agent-stacks.md) | `stack`, `push_stack` |
| Create PRs and interact with GitHub | [PRs and GitHub commands](agent-prs.md) | `github`, running `gh` and the pinned `gh stack` extension |

`import_source(source, revision?, into)` runs inline in `std/llm-step`. It accepts an HTTPS repository and a branch, full ref, or full commit hash. Omitting `revision` selects the default branch. Keep
`/import` for local paths.
## How the pieces fit

For each tool call:
A [conversation](chat.md) contains source gitlinks pointing to code commits. Importing attaches an existing commit at a new path. Editing that source advances its gitlink. Publishing sends its exact
commit and history from the server's Git store to a remote branch; it does not move the source gitlink.

1. Resolve the revision with `git ls-remote`, using the agent's existing Git
binary. A full commit hash needs no lookup.
2. Save the chosen hash H and provenance in the conversation's `tool.start`
payload. Resumed attempts reuse H; concurrent attempts use the first saved
observation. A new call resolves the remote again.
3. Run `caos import-git <source> H`. This sends
`POST /git/import {"source": "<https-url>", "commit": "H"}`.
4. After the server returns `{"commit": "H"}`, atomically attach the snapshot,
its provenance, and the tool result:
A registered stack orders these source gitlinks and remembers the predecessor each layer was based on. The `stack` tool rebases or merges using Git objects, pausing conflicts in a separate draft that
the agent can edit and continue. `push_stack` publishes the layers' branches through the same server path as a single-branch push.

```text
imports/repo/main gitlink -> H
imports/repo/main.source.json provenance
```
The `github` tool runs a worker containing GitHub CLI. It manages remote metadata after branches exist. It needs no source checkout for PR creation, review, or linking existing PR URLs. Source
restacking and branch pushes remain CAOS operations.

The destination and provenance path must both be unused. An import creates an unchanged snapshot; it does not merge into or advance another source. Provenance records the repository, requested
revision, commit, observation time, and default branch when known. For `origin/main`, choose the repository from the selected source's provenance and import `main` at a fresh path.
Stack publication is independent of PRs. It pushes branches and records their results; it does not create PRs or GitHub stack membership. The generic `github` tool can manage those separately.
Automatically submitting all PRs for a stack is a follow-up described in the [PR design](agent-prs.md#prs-for-a-stack).

The [server endpoint](git-import.md) fetches H and its full history into private staging, verifies them, and publishes the complete pack into the server store. It uses verified complete imports as
negotiation tips; standalone trees and blobs may still be downloaded again. A completion marker for the same URL and H skips fetch and verification. The endpoint handles object availability; callers
handle ref resolution and conversation state.
## Credentials

Supply the token through the existing secret store:
Supply a GitHub token through the existing secret store when launching the TUI:

```text
# .caos-secrets/github-token
Expand All @@ -42,21 +35,13 @@ reader=std/llm-step
reader=std/github
```

Keep the value file ignored and run `caos secrets` to initialize its entropy. The agent uses `/secret/github-token` for GitHub ref lookup and passes `--github-token-file=/secret/github-token` to
`import-git`. The command forwards it in the sensitive `X-Caos-Git-Token` header; the server does not look up the calling job's secrets.
Put the token value in an ignored file and run `caos secrets` to initialize its entropy. `std/llm-step` uses the token for GitHub ref lookup and forwards it to the server for imports and pushes.
`std/github` passes it to `gh` as `GH_TOKEN`.

Ref lookup and fetch share a repository-scoped Git credential helper. Tokens stay out of URLs, Git config, saved arguments, provenance, and logs. Automatic GitHub credentials apply only to
`github.com` on the default HTTPS port. Public imports need no token. Importing needs neither `gh` nor another worker.
## Local work and recovery

## Publishing
Use `/checkout` to edit a source locally. Commit the edits with Git, then use `/import` to attach the result at a new conversation path. Ask the agent to integrate that imported commit into the
intended source. See [local editing](chat.md#viewing-files-and-working-locally) for the commands.

[Branch publication](agent-publish.md) uses POST /git/push, caos push-git and publish_source to push exact commits directly from the server with an expected-head lease. The github tool runs gh with an
explicit repository for PRs, issues, review and stack metadata.

[Stack operations](agent-stacks.md) register ordered source gitlinks, remember each layer's predecessor, and merge or rebase them using Git objects. Conflicts pause with a separate draft gitlink and
report. The agent edits the draft and explicitly continues; finished source history contains no .caos/conflicts or draft editing commits.

push_stack pushes registered layers through the same server path as publish_source, recording each branch's result. Stack pushing needs no GitHub worker and creates no PRs or GitHub stack membership.
PR automation is a separate follow-up.

The TUI's /pr and /publish-branch commands are removed. /import remains for local paths. Older non-stack merge operations still use the legacy source-tree conflict ledger.
Imports pin the resolved commit for each call. Pushes pin the source commit and expected remote head before sending. GitHub commands record each invocation so a worker retry does not silently repeat a
write. The linked designs describe each recovery path and what the agent does when the remote outcome is uncertain.
9 changes: 4 additions & 5 deletions design/agent-harness.md
Original file line number Diff line number Diff line change
Expand Up @@ -360,11 +360,10 @@ points is the caller's tree's business, not this client's (`design/chat.md`,
and freezes redraws for native terminal text selection. `/checkout <gitlink>
[directory]` checks out the named code commit as a detached HEAD in a clean
local checkout. `Ctrl+H` opens the keyboard and slash-command reference.
Publication uses the agent's publish_source and github tools. The
server pushes the selected code commit; the GitHub worker handles PRs and
stacks. See [publication](agent-publish.md) for frozen inputs, leases and
recovery. The TUI's /pr and /publish-branch are removed. Publishing source
commits never mutates the local checkout.
Publication uses the agent's publish_source and push_stack tools. The
server pushes code commits; the GitHub worker handles PRs and other GitHub
metadata. See [GitHub interactions](agent-github.md) for the designs and recovery.
Publishing source commits never mutates the local checkout.

### Superseded protocol detail

Expand Down
33 changes: 33 additions & 0 deletions design/agent-import.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
# Importing remote source

Part of [GitHub interactions](agent-github.md). This page describes the agent workflow; [git-import.md](git-import.md) describes the server endpoint and fetch negotiation.

`import_source(source, revision?, into)` runs inline in `std/llm-step`. It accepts an HTTPS repository and a branch, full ref, or full commit hash. Omitting `revision` selects the default branch. Use
`/import` for local paths.

For each tool call:

1. Resolve the revision with `git ls-remote`, using the agent's existing Git
binary. A full commit hash needs no lookup.
2. Save the chosen hash H and provenance in the conversation's `tool.start`
payload. Resumed attempts reuse H; concurrent attempts use the first saved
observation. A new call resolves the remote again.
3. Run `caos import-git <source> H`. This sends
`POST /git/import {"source": "<https-url>", "commit": "H"}`.
4. After the server returns `{"commit": "H"}`, atomically attach the snapshot,
its provenance, and the tool result:

```text
imports/repo/main gitlink -> H
imports/repo/main.source.json provenance
```

The destination and provenance path must both be unused. An import creates an unchanged snapshot; it does not merge into or advance another source. Provenance records the repository, requested
revision, commit, observation time, and default branch when known. For `origin/main`, choose the repository from the selected source's provenance and import `main` at a fresh path.

The [server endpoint](git-import.md) fetches H and its full history into private staging, verifies them, and publishes the complete pack into the server store. It uses verified complete imports as
negotiation tips; standalone trees and blobs may still be downloaded again. A completion marker for the same URL and H skips fetch and verification. The endpoint handles object availability; callers
handle ref resolution and conversation state.

Configure the [GitHub token](agent-github.md#credentials) for private GitHub repositories. The agent uses it for ref lookup and passes `--github-token-file=/secret/github-token` to `import-git`, which
forwards the token to the server for the fetch. Public imports need no token.
76 changes: 76 additions & 0 deletions design/agent-prs.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
# Pull requests and GitHub commands

Part of [GitHub interactions](agent-github.md). CAOS publishes branches from the server; the `github` tool runs GitHub CLI to create and update PRs, read reviews, and work with issues and comments.

## GitHub worker

`std/github` contains Git, `gh`, and the pinned `github/gh-stack` v0.1.1 extension. It is registered as a built-in tool, available without a project-defined `caos-tools` entry.

The tool is `github(repository, args, stdin?)`. `args` is an argument array passed directly to `gh`; it is never interpolated into a shell command. Return exit status, stdout and stderr through
ordinary tool results. This covers issues, comments, PR creation/editing and stack operations without separate wrappers for each GitHub action. Pass PR bodies through stdin (`--body-file -`).

The worker sets `GH_REPO` explicitly and reads `GH_TOKEN` from its granted `/secret/github-token`. Use the [shared token setup](agent-github.md#credentials), granting it to both `std/github` and
`std/llm-step`. The latter uses it for import/push and includes that identity in the model turn’s cache key. The agent carries the GitHub worker source and evaluates it when called, so secret marking
of the child worker does not alter the agent’s own reader identity. Use an isolated temporary GitHub configuration and disable prompts. Install the extension in the image. The worker needs no source
checkout or local branches for the operations below.

## Invocation recovery

Identical GitHub commands can observe different remote state, and comments must not be posted again when a worker retries. The harness therefore binds a stable, unique invocation ID into every GitHub
request. A new tool call gets a new ID; resuming the same call retains it. Normal result caching then belongs to that observation, rather than to the command arguments indefinitely.

A unique cache key alone does not prevent duplicate execution. Before running `gh`, the worker atomically claims a small record under `refs/caos/github/<invocation-id>` using the existing Git
compare-and-swap transport. The record binds the entire pinned ArgTree (arguments, worker image, secret identity and salt) and a unique attempt ID. Recovery dispatches the stored task, including its
original worker image. Reusing an invocation with a different ArgTree is an error; changed worker or secret identity requires a new invocation, after reconciling any earlier write. This preserves
result-cache identity and prevents sharing results across credentials.

A failed claim with no retained ref is a retryable job failure. Once gh has run, retry output storage and result-CAS bookkeeping up to three times, without rerunning gh. Exhausted bookkeeping leaves
the claim uncertain.

Only the attempt that owns the claim executes the command. Record the exit status and output hashes afterwards; completed duplicates return that result.

If a claim exists without a recorded result, a duplicate reports pending or uncertain and does not execute `gh`. Never expire or steal that claim based on elapsed time. A crash between claiming and
execution can therefore require inspection even when nothing happened. This provides at most one wrapper execution per invocation, not a transaction or exactly-once guarantee at GitHub.

Apply this rule to all commands, including reads, to avoid classifying arbitrary `gh api` requests as safe or unsafe. After an uncertain write, the agent uses a new read invocation to inspect GitHub,
then decides the remaining action. An absent PR or comment is not proof that a still-running command cannot create it. If reconciliation cannot establish the outcome, leave it uncertain rather than
repeat the write. Failure of a multi-step command can leave partial changes. The tool's exit status and transcript must not claim that nothing happened.

## PR workflow

For a single PR:

1. Integrate required updates and test the chosen source gitlink.
2. Call [`publish_source`](agent-publish.md) with its path, repository and remote branch. Continue
after a confirmed push.
3. Find an open PR with `gh pr list --head <branch>`; select explicitly if
several match. If absent, use `gh pr create --repo <repository>
--head <branch> --base <base> --title <title> --body-file -`, passing the
body through the tool's stdin. Supply these arguments explicitly so
creation needs no local repository.
4. Check the PR's URL, head commit and base with `gh pr view <url> --json ...`,
and retain the result in the conversation.

Later source edits advance the same branch through `publish_source`, updating the existing PR. Preserve human-edited titles and descriptions unless an edit was requested; use `gh pr edit` for
requested metadata or base changes. Use `gh pr view`, `gh pr checks`, and `gh api` to read discussion, review threads and checks, and the corresponding CLI/API calls for requested replies. Create
ready-for-review PRs by default. A failed PR creation leaves the successful branch push intact; recovery follows the invocation rules above.

## PRs for a stack

[Stack publication](agent-stacks.md#pushing-branches) produces ordinary remote branches. For example, a two-layer stack based on remote `main` maps to:

| Source gitlink | PR head branch | PR base branch |
| --- | --- | --- |
| `feature/01-core` | `feature/01-core` | `main` |
| `feature/02-ui` | `feature/02-ui` | `feature/01-core` |

The base gitlink has no PR. The first PR targets the remote integration branch; each later PR targets the preceding layer's branch. PR numbers are assigned by GitHub and can be discovered from the
repository and branch names. Keep the returned URLs in the conversation for later review and updates.

The agent can perform these steps with the generic `github` tool after a confirmed `push_stack`. There is no dedicated operation that creates or repairs all PRs for a stack. That automation remains a
follow-up.

GitHub stack membership is also separate from branch publication. Once PRs exist, the worker can pass their URLs to `gh stack link`. Using PR URLs avoids the extension's local-branch push workflow;
CAOS remains responsible for moving the branch refs. The source gitlinks and `stack.json` remain the inputs to CAOS restacking, not GitHub's PR metadata.

Implementation: [GitHub worker](../std/github/src/main.rs) and [agent tool](../std/llm-step/src/github.rs).
Loading
Loading