Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
0133cb4
chore(porch): 12 init pir
pseudoseed Aug 21, 2026
28e764f
[PIR #12] Plan draft: gitea pr-search, pr-diff, and the pr-exists hang
pseudoseed Aug 21, 2026
362cab3
chore(porch): 12 plan-approval gate-requested
pseudoseed Aug 21, 2026
102dd14
chore(porch): 12 plan-approval gate-approved
pseudoseed Aug 21, 2026
594bd56
chore(porch): 12 implement phase-transition
pseudoseed Aug 21, 2026
63c9807
[PIR #12] fix(gitea): answer pr-exists in one request instead of ~17 …
pseudoseed Aug 21, 2026
d066687
[PIR #12] fix: enable the gitea concepts, and stop degrading silently
pseudoseed Aug 21, 2026
bbc4ebe
[PIR #12] test+docs: pin the endpoints, the head.label behaviour, and…
pseudoseed Aug 21, 2026
64cb220
[PIR #12] fix(doctor): report tea for every gitea concept, not echo o…
pseudoseed Aug 21, 2026
e018fee
[PIR #12] docs: builder thread for the implement phase
pseudoseed Aug 21, 2026
bb40271
chore(porch): 12 dev-approval gate-requested
pseudoseed Aug 21, 2026
6da756b
chore(porch): 12 dev-approval gate-approved
pseudoseed Aug 21, 2026
13c8cbe
chore(porch): 12 review phase-transition
pseudoseed Aug 21, 2026
c359c60
[PIR #12] Review + retrospective
pseudoseed Aug 21, 2026
2e784d2
chore(porch): 12 record PR #19
pseudoseed Aug 21, 2026
64c50fe
chore(porch): 12 review build-complete
pseudoseed Aug 21, 2026
f541a94
[PIR #12] docs: builder thread for the review phase
pseudoseed Aug 21, 2026
ed297bf
[PIR #12] fix: address review round 1 (claude, 4 non-blocking findings)
pseudoseed Aug 21, 2026
136fb77
chore(porch): 12 pr gate-requested
pseudoseed Aug 21, 2026
269d2d7
[PIR #12] docs: porch reports a SKIPPED lane as an approval
pseudoseed Aug 21, 2026
8d4e181
chore(porch): 12 pr gate-approved
pseudoseed Aug 21, 2026
bbd64aa
chore(porch): 12 protocol complete
pseudoseed Aug 21, 2026
5573cbd
[PIR #12] docs: the porch verdict hole has two routes, not one (#20)
pseudoseed Aug 21, 2026
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
50 changes: 50 additions & 0 deletions .claude/skills/forge/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,56 @@ Built-in presets: `github` (default), `gitlab` (via `glab`), `gitea` (via `tea`)

**Note:** Non-GitHub presets are best-effort. Output schemas may differ from GitHub's JSON contracts. Non-conforming JSON returns `null` — consumers handle this gracefully. Override individual concepts if a preset doesn't match your CLI version.

### Gitea / Forgejo specifics

Forgejo has no GitHub-style PR search and charges its `/pulls` list endpoint per
returned PR object (~0.65s each, measured against Forgejo 15.x), so the gitea
scripts avoid list endpoints wherever a targeted one exists.

| Concept | How gitea answers it |
|---|---|
| `pr-exists` | `GET pulls/{base}/{head}` — one request. Base is `CODEV_PR_BASE`, else the repo's default branch. |
| `pr-search` | `head:` queries use the same base/head lookup; issue-number queries search `issues?type=pulls&q=` and then resolve each match. |
| `pr-diff` | `pulls/{n}.diff`, or `pulls/{n}/files` for `CODEV_DIFF_NAME_ONLY=1`. |
| `recently-merged` | `issues?type=pulls&state=closed&since=` (a server-side window), then one `pulls/{n}` per match for the head branch. |
| `team-activity`, `on-it-timestamps` | Disabled, permanently. Both are `gh api graphql` pass-throughs and Forgejo has no GraphQL. Callers say so on stderr rather than returning empty. |

**pr-search query grammar.** The query is parsed, not forwarded. Understood
terms: `head:<branch>`, `is:open`, `is:merged`, `is:closed`, `in:body`, and a
bare issue number (`123` or `#123`). With no `is:` qualifier the search spans
every state, so a merged PR is findable after the fact. Anything outside the
grammar returns `[]` and says so on stderr rather than guessing.

**A merged PR's branch name.** Gitea rewrites `head.ref` to `refs/pull/N/head`
once a merged PR's source branch is deleted, but `head.label` keeps the branch
name. The gitea scripts read `head.label` first, which is what lets `pr-exists`
and `pr-search head:` still find a merged PR.

**Base branches other than the default.** `pr-exists` and `pr-search head:` need
a base branch. They use the repository's default unless `CODEV_PR_BASE` is set,
so a PR targeting an integration branch needs that variable.

### Environment overrides

| Variable | Default | Effect |
|---|---|---|
| `CODEV_REPO` | derived from `origin` | `owner/repo` for the gitea scripts |
| `CODEV_PR_BASE` | the repo's default branch | base branch for `pr-exists` / `pr-search head:` |
| `CODEV_FORGE_TIMEOUT` | 60 | seconds before a single `tea api` call is killed and reported |
| `CODEV_FORGE_PAGED_DEADLINE` | 120 | seconds before a paged walk stops early (exit 3) |
| `CODEV_FORGE_CONCURRENCY` | 8 | parallel PR fetches |
| `CODEV_FORGE_MERGED_DAYS` | 7 | `recently-merged` window when `CODEV_SINCE_DATE` is unset |
| `CODEV_FORGE_MERGED_MAX` | 300 | merged PRs `recently-merged` will resolve before refusing |
| `CODEV_FORGE_SEARCH_MAX` | 10 | PRs `pr-search` resolves for one issue number |

### Exit statuses

`0` is an answer and `1` is a failure, as usual. **`3` means the result was
truncated**, and the concept prints nothing on stdout when it returns it: a
partial list is indistinguishable from a complete one once printed, so "nothing
matched" (`[]`, status 0) and "I stopped looking" (status 3) are deliberately
different. `2` is a missing or unusable input.

### Disabling concepts

Set a concept to `null` to disable it:
Expand Down
50 changes: 50 additions & 0 deletions .codex/skills/forge/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,56 @@ Built-in presets: `github` (default), `gitlab` (via `glab`), `gitea` (via `tea`)

**Note:** Non-GitHub presets are best-effort. Output schemas may differ from GitHub's JSON contracts. Non-conforming JSON returns `null` — consumers handle this gracefully. Override individual concepts if a preset doesn't match your CLI version.

### Gitea / Forgejo specifics

Forgejo has no GitHub-style PR search and charges its `/pulls` list endpoint per
returned PR object (~0.65s each, measured against Forgejo 15.x), so the gitea
scripts avoid list endpoints wherever a targeted one exists.

| Concept | How gitea answers it |
|---|---|
| `pr-exists` | `GET pulls/{base}/{head}` — one request. Base is `CODEV_PR_BASE`, else the repo's default branch. |
| `pr-search` | `head:` queries use the same base/head lookup; issue-number queries search `issues?type=pulls&q=` and then resolve each match. |
| `pr-diff` | `pulls/{n}.diff`, or `pulls/{n}/files` for `CODEV_DIFF_NAME_ONLY=1`. |
| `recently-merged` | `issues?type=pulls&state=closed&since=` (a server-side window), then one `pulls/{n}` per match for the head branch. |
| `team-activity`, `on-it-timestamps` | Disabled, permanently. Both are `gh api graphql` pass-throughs and Forgejo has no GraphQL. Callers say so on stderr rather than returning empty. |

**pr-search query grammar.** The query is parsed, not forwarded. Understood
terms: `head:<branch>`, `is:open`, `is:merged`, `is:closed`, `in:body`, and a
bare issue number (`123` or `#123`). With no `is:` qualifier the search spans
every state, so a merged PR is findable after the fact. Anything outside the
grammar returns `[]` and says so on stderr rather than guessing.

**A merged PR's branch name.** Gitea rewrites `head.ref` to `refs/pull/N/head`
once a merged PR's source branch is deleted, but `head.label` keeps the branch
name. The gitea scripts read `head.label` first, which is what lets `pr-exists`
and `pr-search head:` still find a merged PR.

**Base branches other than the default.** `pr-exists` and `pr-search head:` need
a base branch. They use the repository's default unless `CODEV_PR_BASE` is set,
so a PR targeting an integration branch needs that variable.

### Environment overrides

| Variable | Default | Effect |
|---|---|---|
| `CODEV_REPO` | derived from `origin` | `owner/repo` for the gitea scripts |
| `CODEV_PR_BASE` | the repo's default branch | base branch for `pr-exists` / `pr-search head:` |
| `CODEV_FORGE_TIMEOUT` | 60 | seconds before a single `tea api` call is killed and reported |
| `CODEV_FORGE_PAGED_DEADLINE` | 120 | seconds before a paged walk stops early (exit 3) |
| `CODEV_FORGE_CONCURRENCY` | 8 | parallel PR fetches |
| `CODEV_FORGE_MERGED_DAYS` | 7 | `recently-merged` window when `CODEV_SINCE_DATE` is unset |
| `CODEV_FORGE_MERGED_MAX` | 300 | merged PRs `recently-merged` will resolve before refusing |
| `CODEV_FORGE_SEARCH_MAX` | 10 | PRs `pr-search` resolves for one issue number |

### Exit statuses

`0` is an answer and `1` is a failure, as usual. **`3` means the result was
truncated**, and the concept prints nothing on stdout when it returns it: a
partial list is indistinguishable from a complete one once printed, so "nothing
matched" (`[]`, status 0) and "I stopped looking" (status 3) are deliberately
different. `2` is a missing or unusable input.

### Disabling concepts

Set a concept to `null` to disable it:
Expand Down
Loading
Loading