Skip to content
Draft
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
5 changes: 5 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,11 @@ needs a release.
Ready-made routes for every supported case, including multi-round pull request review,
are in **[docs/routes.md](./docs/routes.md)** and served from `GET /v1/route-templates`.

Assignment templates can start an implementation when a Linear or GitHub issue is
assigned to a configured bot. See [setup and current scope](./docs/routes.md#implement-an-assigned-issue).
The [six-release plan](./docs/plans/assigned-ticket-pr-feedback.md) covers durable work,
verified PR evidence, and continuation in the same Hermes session.

## How it fits together

```
Expand Down
24 changes: 19 additions & 5 deletions docs/api.md
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,8 @@ DELETE /v1/projects/:id

```jsonc
// Linear
{ "id": "taplands", "provider": "linear", "filters": { "team": "ENG" } }
{ "id": "taplands", "provider": "linear",
"filters": { "team": "ENG", "repository": "acme/www" } }

// GitHub
{ "id": "www", "provider": "github",
Expand Down Expand Up @@ -189,14 +190,18 @@ DELETE /v1/routes/:id

"target": {
"agentRef": { "profile": "product" }
// or, for either pull request trigger — matches the account being
// or, for PR triggers and ticket triggers with provider "github":
// matches the account being
// assigned to the item or asked to review it:
// "agentRef": { "githubLogin": "acme-reviewer-bot" }
// or, for ticket triggers with provider "linear":
// "agentRef": { "linearUserId": "user-uuid", "linearWorkspaceId": "org-uuid" }
},

"execution": {
"prompt": "Review {{ticket.ref}}: {{ticket.title}}\n\n{{ticket.body}}",
"requireApproval": false, // uses Hermes' own approval gate
"requireRepository": false, // assigned implementation templates set true
"modelOverride": null, // null = the profile's own model
"timeoutSeconds": 1800,
"approvalTimeoutSeconds": 3600 // optional; how long a gate may wait
Expand Down Expand Up @@ -398,11 +403,19 @@ PUT /v1/routes/{id}
```

`PUT` replaces the route entirely rather than merging fields. A route is a
single decision, and its parts constrain each other — a `githubLogin` target is
valid on a pull request trigger and rejected on a ticket one — so a partial
single decision, and its parts constrain each other — a Linear identity target needs
both user and workspace IDs and a Linear ticket trigger — so a partial
update could walk a route through states the validator rejects as a whole. The
body is validated as the complete rule it will become.

With `execution.requireRepository: true`, enabled routes also require a registered
project of the matching provider, a valid `owner/repo` repository, and exactly one
enabled agent resolving the target in the organization's inventory. Linear projects
use `filters.repository`; GitHub projects use `filters.owner` and `filters.repo`.
Invalid or ambiguous setup returns 400 on both creation and replacement. Disabled
drafts skip this contextual check. Optional `filters.repository`, when supplied on a
project, must be an `owner/repo` string.

The id in the path wins over any id in the body, so a copy-pasted definition
cannot rewrite a different route. `PUT` to an id that does not exist is a `404`,
not an upsert.
Expand Down Expand Up @@ -493,7 +506,8 @@ than deferred — nothing will retry it, so the caller is owed the reason.
## Agents and runners

```http
GET /v1/agents Hermes profiles, as discovered by the runner (incl. avatar_url)
GET /v1/agents Hermes profiles, as discovered by the runner (incl. avatar_url,
linear_user_id and linear_workspace_id)
GET /v1/runners registered runners, with health and a `stale` flag
```

Expand Down
12 changes: 11 additions & 1 deletion docs/dashboard.md
Original file line number Diff line number Diff line change
Expand Up @@ -194,12 +194,22 @@ asks only for what the template declares, and asks for it with the right control
| `<PROJECT_ID>` | a dropdown of registered projects |
| `<AGENT_PROFILE>` | a dropdown of discovered agents |
| `<AGENT_GITHUB_LOGIN>` | filled from the selected agent |
| `<LINEAR_USER_ID>`, `<LINEAR_WORKSPACE_ID>` | editable fields filled from the selected agent |
| anything else | a text field |

Free text where the API already knows the answer produces a route that is structurally
valid and can never match — a typo'd project id fires nothing, silently, forever.
Selecting the agent is also what fills a `githubLogin` target, so the two cannot drift
apart the way two independent fields would.
apart the way two independent fields would. Selecting a Linear agent also fills its
user and workspace IDs from runner inventory. Configure those IDs in the runner;
the Agents table displays them. Editing a route preserves its identity target.

The assigned implementation templates limit project choices to the matching provider
and explain that every currently assigned open issue is eligible. For a Linear
project, **Add project** includes an **Implementation repository** field (`owner/repo`).
The API rejects enabling an implementation route with missing repository context or
an unknown/ambiguous agent. See [assigned issue setup](./routes.md#implement-an-assigned-issue)
for the single-runner limitation and the current release's behavior.

Under the prompt is the list of variables the runner substitutes at dispatch. Clicking
one inserts it at the cursor. This matters more than it looks: the runner deliberately
Expand Down
4 changes: 4 additions & 0 deletions docs/deploy-cloud.md
Original file line number Diff line number Diff line change
Expand Up @@ -238,6 +238,10 @@ docker build --platform linux/amd64 -t sentinel0-cloud .

## Adding a migration

Assignment routing adds `008_linear_agent_identity.sql`. Apply it with the API deploy
before the updated runner/dashboard; it adds nullable agent identity columns and
does not rewrite existing routes. See [release order and rollback](./releasing.md#after-a-deploy).

Add `packages/cloud-api/src/migrations/002_whatever.sql`. Nothing else — the migrator
picks up any `.sql` file it has not already applied and records it in
`schema_migrations`.
Expand Down
9 changes: 8 additions & 1 deletion docs/getting-started.md
Original file line number Diff line number Diff line change
Expand Up @@ -107,17 +107,24 @@ Neither is recoverable. Store them now.

## 4. Configure what should happen

Three shapes of route cover most of what you will want:
These routes cover the common starting points:

| You want | `trigger.type` | `match` |
|---|---|---|
| a ticket gets a label | `ticket` | `labels` or `labelsAdded` |
| an issue is assigned to the implementer | `ticket` | target by GitHub login or scoped Linear identity |
| a PR is assigned to someone | `pr_event` | `assignees` or `assigneesAdded` |
| an agent is asked to review a PR | `pr_review_requested` | target by `githubLogin` |

Routes fire **once per item** by default and mark their work with `sentinel0:` labels,
so an agent's own commits and comments cannot retrigger the route that started them.

For assigned implementation, follow [the assignment setup](./routes.md#implement-an-assigned-issue):
declare the bot identity in the Hermes profile configuration and bind Linear projects
to an implementation repository. This starts the initial run and source summary;
automatic PR feedback continuation is a later release. `preflight` checks identity
configuration shape, not whether the configured bot actually owns the account.

**[routes.md](./routes.md) is the full reference** — every trigger, every match clause,
the loop guard, and a ready-made route for each supported case. You can also fetch
those directly:
Expand Down
Loading
Loading