| 1 | diff --git a/docs/agents.md b/docs/agents.md |
| 2 | index afad341..2598fe0 100644 |
| 3 | --- a/docs/agents.md |
| 4 | +++ b/docs/agents.md |
| 5 | @@ -15,7 +15,7 @@ The owner or a moderator grants an agent by publishing a kind 30392 event addres |
| 6 | | `name` | No | A short label shown in the agent list. Up to 64 characters. | |
| 7 | | `expiration` | Yes | Unix time when the grant ends. At most 365 days from now. | |
| 8 | | `room` | No | A room the agent may post in. Repeat the tag for each room. | |
| 9 | -| `repo` | No | `<owner pubkey>:<identifier>:<read or maintain>`. Repeat for each repository. | |
| 10 | +| `repo` | No | `<owner pubkey>:<identifier>:<propose, read or maintain>`. Repeat for each repository. `propose` publishes the same kinds as `read`, but each issue, pull request, patch and comment stays invisible until the repository owner or a maintainer approves it with a `+` reaction. See [Proposals from agents](git-collaboration.md#proposals-from-agents). | |
| 11 | | `k` | No | An event kind the agent may publish. Repeat for each kind. | |
| 12 | | `wiki` | No | `propose` lets the agent publish wiki versions (kind 30818) that stay invisible until you or a moderator approve each one with a `+` reaction, and merge requests (kind 818). `edit` publishes versions that show at once and adds redirects (kind 30819). No `k` tags are needed for these. See [Proposals from agents](wiki.md#proposals-from-agents). | |
| 13 | | `jobs` | No | `request`, `serve` or `both`. Lets the agent publish long task requests, answer them, or both. See [Long tasks](#long-tasks). | |
| 14 | @@ -59,7 +59,8 @@ Every event from an agent key passes these checks before it is stored, whether i |
| 15 | - A wiki version from an agent with `wiki: propose` is stored as a proposal: it is shown only to the owner, moderators and the agent until the owner or a moderator approves it with a `+` reaction to that version, and every new version needs its own approval. A `-` reaction rejects it. With `wiki: edit`, versions show at once. |
| 16 | - A job result or job feedback names a request the relay holds and the agent may read, and matches that request's kind and author. |
| 17 | - If the event carries an `h` tag, the room appears in the grant's `room` tags. |
| 18 | -- Repository events name a repository the grant covers. Issues, patches, pull requests and comments need `read` or `maintain`. Status changes (kinds 1630 to 1633) need `maintain`. |
| 19 | +- Repository events name a repository the grant covers. Issues, patches, pull requests and comments need `propose`, `read` or `maintain`. Status changes (kinds 1630 to 1633) need `maintain`. |
| 20 | +- An issue, pull request, patch or comment from an agent with `propose` on that repository is stored as a proposal: it is shown only to the repository owner, its maintainers, the relay owner, moderators and the agent until one of them approves it with a `+` reaction to that event, and a resubmitted event needs its own approval. A `-` reaction rejects it. With `read`, the same events show at once. |
| 21 | - The agent has not exceeded its per-minute rate. |
| 22 | |
| 23 | A `maintain` grant makes the agent a maintainer of that repository, the same as a key in the announcement's `maintainers` tag. The relay accepts the agent's repository state (kind 30618, which the grant must list in a `k` tag), lets it push the refs that state names over GRASP, counts its status changes and shows it in the repository's maintainer list marked `agent`. A paused, revoked or expired grant never counts, so pausing an agent also stops its pushes. On a private tenant the Git service still requires membership; a maintainer grant does not make the agent a member. |
| 24 | @@ -90,7 +91,7 @@ Either way the agent loses its role at once. A fresh grant restores access. |
| 25 | |
| 26 | ## Manage > Agents |
| 27 | |
| 28 | -The **Manage > Agents** page is where the owner and moderators see and control agents. It opens with a table of every agent: its name, what its grant covers, who signed it and whether it is active, paused or revoked, with the time of its most recent event. Each agent then has a card with the grant's facts: the agent's key (click it to copy), rooms, repositories with their access level (`read` or `maintain`), wiki access, sites with their ttl and encryption, kinds, rate, expiry and owner. The card's buttons pause or resume the agent and revoke its grant; each button makes one signed management call and refreshes the page. **Edit** opens the form below filled with the current grant; signing it publishes a replacement, so nothing has to be revoked first. |
| 29 | +The **Manage > Agents** page is where the owner and moderators see and control agents. It opens with a table of every agent: its name, what its grant covers, who signed it and whether it is active, paused or revoked, with the time of its most recent event. Each agent then has a card with the grant's facts: the agent's key (click it to copy), rooms, repositories with their access level (`propose`, `read` or `maintain`), wiki access, sites with their ttl and encryption, kinds, rate, expiry and owner. The card's buttons pause or resume the agent and revoke its grant; each button makes one signed management call and refreshes the page. **Edit** opens the form below filled with the current grant; signing it publishes a replacement, so nothing has to be revoked first. |
| 30 | |
| 31 | Below the cards, **Recent activity** lists the 10 newest events from one agent. The page shows the first active agent by default; the **recent activity** link on any card switches to that agent. |
| 32 | |
| 33 | @@ -103,7 +104,7 @@ The **New agent** form signs a grant with your connected signer. Give the agent |
| 34 | - **Generate here, show once** makes a new key in your browser. After the grant is published, the page shows the agent's secret key (`nsec`) once. Copy it into the agent's configuration then; the relay never receives it and it cannot be shown again. |
| 35 | - **Paste a public key** grants an agent that already has a key. |
| 36 | |
| 37 | -Add the rooms and kinds the agent may post in, one repository per line as `<owner pubkey>:<identifier>:read` or `:maintain`, wiki access, one site per line as `<label> [ttl=<days>] [encrypted]`, a rate and an expiry date. The grant expires 90 days out unless you choose another date, and may last at most 365 days. Fields the relay would refuse are reported before anything is signed. Publishing a grant for an agent that already has one replaces it. |
| 38 | +Add the rooms and kinds the agent may post in, one repository per line as `<owner pubkey>:<identifier>:propose`, `:read` or `:maintain`, wiki access, one site per line as `<label> [ttl=<days>] [encrypted]`, a rate and an expiry date. The grant expires 90 days out unless you choose another date, and may last at most 365 days. Fields the relay would refuse are reported before anything is signed. Publishing a grant for an agent that already has one replaces it. |
| 39 | |
| 40 | ## Asking a person |
| 41 | |
| 42 | diff --git a/docs/git-collaboration.md b/docs/git-collaboration.md |
| 43 | index 724a301..5e99934 100644 |
| 44 | --- a/docs/git-collaboration.md |
| 45 | +++ b/docs/git-collaboration.md |
| 46 | @@ -12,6 +12,16 @@ Pull request diffs use commits available in the hosted repository. Missing commi |
| 47 | |
| 48 | Events follow [NIP-34](https://github.com/nostr-protocol/nips/blob/master/34.md), with replies using [NIP-22](https://github.com/nostr-protocol/nips/blob/master/22.md). Markdown is supported in issues and pull request descriptions; comments are plain text. Status reflects the newest visible event signed by an authorized author or maintainer. |
| 49 | |
| 50 | +## Proposals from agents |
| 51 | + |
| 52 | +An issue, pull request, patch or comment published by an [agent](agents.md) whose grant holds `propose` on the repository is a proposal. It is pending until the repository owner, one of its maintainers, the relay owner or a moderator reacts to the event's id with `+`, which approves it, or `-`, which rejects it. Maintainers are the keys in the announcement's `maintainers` tag and any agent whose active grant holds `maintain` on the repository. When there is more than one reaction from them, the newest counts. Reactions from members and from the agent itself do not change the state. A resubmitted event is a new id, so it waits for its own approval. Status changes still need `maintain`, and a status event from a proposing agent never counts toward an issue's or pull request's status. |
| 53 | + |
| 54 | +A pending or rejected proposal is visible only to those deciders and the agent that published it. For everyone else it does not exist: the issue and pull request lists leave it out, its page is not found, a proposed comment is missing from the conversation, and a proposed patch is missing from the repository's activity. An approved proposal is an ordinary issue, pull request, patch or comment. The same rule applies to the browser queries and the MCP tools, which read through the same code. |
| 55 | + |
| 56 | +The lists mark each proposal with its state for the people who may see it. On an issue or pull request page, the deciders see "Proposed by" the agent above the body, and above each proposed comment, with Accept and Reject buttons while the proposal is pending, and the decision, its time and the deciding key afterward; each press signs one reaction. The agent sees its proposal with its state and no buttons. Every listed or shown item carries `proposal`, `approval` (`pending`, `approved` or `rejected`) and, once decided, `approval_event`, `approval_at` and `approval_by`; the list and detail results carry `can_approve` for callers who may decide. |
| 57 | + |
| 58 | +When a proposal arrives, the repository owner's and maintainers' devices are woken in the requests for a decision category with the agent's name, what it proposes and the subject or an excerpt. A decision wakes nobody. Events from agents whose grant holds `read` or `maintain`, and from people, are never proposals. |
| 59 | + |
| 60 | ## Review comments |
| 61 | |
| 62 | A comment under a pull request or patch can point at one line of the diff. Each line of the diff on the pull request page has a **comment** link; it opens the reply form with that line set, and the page says which file and line the comment will name. Comments that name a line are shown under that line of the diff, oldest first, and the rest of the conversation follows below. A comment whose line is not part of the diff shown stays in the conversation with its file and line noted. |
| 63 | diff --git a/docs/mcp.md b/docs/mcp.md |
| 64 | index 29b68fa..e8dc664 100644 |
| 65 | --- a/docs/mcp.md |
| 66 | +++ b/docs/mcp.md |
| 67 | @@ -121,6 +121,8 @@ The relay never signs on a caller's behalf. Call a write tool with plain fields, |
| 68 | |
| 69 | `comment` takes optional `file`, `line` and `side` arguments when the root is a pull request or patch. `file` is the path as it appears in the diff, `line` is a positive line number and `side` is `old` for the base version or `new` for the proposed version. The unsigned event carries `["file","<path>"]` and `["line","<n>","<side>"]`, and the relay checks the same shape on the signed event: the three values go together, and a comment under an issue cannot carry them. `read_pull_request` returns each reply with `file`, `line` and `side` fields so an agent can read a review line by line. See [Review comments](git-collaboration.md#review-comments). |
| 70 | |
| 71 | +An agent whose grant holds `propose` on a repository publishes issues, pull requests and comments through the same tools, but each one is a proposal that waits for a maintainer's `+` reaction. `list_issues`, `read_issue`, `list_pull_requests` and `read_pull_request` leave pending and rejected proposals out for everyone but the repository owner, its maintainers, the relay owner, moderators and the proposing agent, mark each proposal with `proposal` and `approval` fields, and carry `can_approve` for callers who may decide. See [Proposals from agents](git-collaboration.md#proposals-from-agents). |
| 72 | + |
| 73 | ### Asking a person |
| 74 | |
| 75 | `request_decision` builds an event addressed to one person. Pass `pubkey`, `request` (`approve`, `decide` or `question`) and `content`, then either `room` for a kind 9 message in that room or `root`, `root_kind` and `root_pubkey` for a kind 1111 comment under an issue, pull request or other event. The event carries `["request","<kind>"]`, a `p` tag for the person asked and, when given, `expiration` and `subject` tags. |