forgejo ops: add org-scoped repo-create verb (POST /orgs/{org}/repos) #218

Closed
opened 2026-06-19 07:21:00 +00:00 by coilyco-ops · 1 comment
Member

Goal

Add an org-scoped repo-create verb to the ward-kdl forgejo ops surface: POST /orgs/{org}/repos (operationId createOrgRepo). Today the only repo-create verb is create repo which resolves to POST /user/repos (personal namespace, and it needs write:user which the bot lacks). There is no way to create a repo inside an org through ward, even though the coilyco-ops bot token already carries write:organization.

Why now

Two repos are blocked on this and cannot be created through tooling: coilyco-bridge/agentic-os-hardware and coilyco-flight-deck/agent-proxy. Tracking: coilysiren/inbox#118.

No token change needed

The bot token (scripts/provision-coilyco-ops-bot.sh, SSM /forgejo/coilyco-ops/api-token) is minted with write:repository write:issue read:user write:organization write:notification. write:organization is exactly what POST /orgs/{org}/repos requires. Do not touch the scopes. This is a missing verb, not a missing permission.

What to implement

Mirror the existing org-label compound resource, which targets /orgs/{org}/labels. Add an org-repo compound resource targeting /orgs/{org}/repos.

  • In the guardfile cmd/ward-kdl/ward-kdl.forgejo.guardfile.kdl, add can create org-repo near the org section. Keep the cmd/ward/opsassets/forgejo.guardfile.kdl copy in sync (follow whatever generate/embed step the repo uses - check the Makefile).
  • Resolve the operationId. The convention is verb plus resource maps to method plus path. If create org-repo does not auto-resolve to createOrgRepo / /orgs/{org}/repos, pin it explicitly with an op the way other verbs pin theirs. Verify the operationId against forgejo.swagger.v1.json and ensure forgejo.swagger.lock.json includes the operation (it currently does not appear to).
  • The verb takes <org> as the required path positional and the same body flags as repo create (--name required, --description, --private, --auto_init, --default_branch, --readme, --gitignores, --license, etc.).
  • Surface renders as ward ops forgejo org-repo create <org> --name <name> ... and ward-kdl ops forgejo org-repo create ....

Acceptance

  • ward-kdl ops forgejo org-repo create coilyco-flight-deck --name __probe__ --dry-run resolves to POST /api/v1/orgs/coilyco-flight-deck/repos with the right body.
  • A real create against a throwaway name in coilyco-flight-deck succeeds and is then cleaned up (the existing delete repo verb, or leave the probe and note it).
  • ward ops forgejo describe lists the new verb.
  • Docs updated: docs/ward-kdl.forgejo.guardfile.md, docs/FEATURES.md, and any opsassets_test.go expectations that enumerate the surface.

Out of scope

  • Org creation and deletion stay human-only (already never).
  • No change to create repo (the user-namespace verb).
  • No token or scope changes.
## Goal Add an org-scoped repo-create verb to the ward-kdl forgejo ops surface: `POST /orgs/{org}/repos` (operationId `createOrgRepo`). Today the only repo-create verb is `create repo` which resolves to `POST /user/repos` (personal namespace, and it needs `write:user` which the bot lacks). There is no way to create a repo inside an org through ward, even though the `coilyco-ops` bot token already carries `write:organization`. ## Why now Two repos are blocked on this and cannot be created through tooling: `coilyco-bridge/agentic-os-hardware` and `coilyco-flight-deck/agent-proxy`. Tracking: coilysiren/inbox#118. ## No token change needed The bot token (`scripts/provision-coilyco-ops-bot.sh`, SSM `/forgejo/coilyco-ops/api-token`) is minted with `write:repository write:issue read:user write:organization write:notification`. `write:organization` is exactly what `POST /orgs/{org}/repos` requires. Do not touch the scopes. This is a missing verb, not a missing permission. ## What to implement Mirror the existing `org-label` compound resource, which targets `/orgs/{org}/labels`. Add an `org-repo` compound resource targeting `/orgs/{org}/repos`. - In the guardfile `cmd/ward-kdl/ward-kdl.forgejo.guardfile.kdl`, add `can create org-repo` near the org section. Keep the `cmd/ward/opsassets/forgejo.guardfile.kdl` copy in sync (follow whatever generate/embed step the repo uses - check the Makefile). - Resolve the operationId. The convention is verb plus resource maps to method plus path. If `create org-repo` does not auto-resolve to `createOrgRepo` / `/orgs/{org}/repos`, pin it explicitly with an `op` the way other verbs pin theirs. Verify the operationId against `forgejo.swagger.v1.json` and ensure `forgejo.swagger.lock.json` includes the operation (it currently does not appear to). - The verb takes `<org>` as the required path positional and the same body flags as `repo create` (`--name` required, `--description`, `--private`, `--auto_init`, `--default_branch`, `--readme`, `--gitignores`, `--license`, etc.). - Surface renders as `ward ops forgejo org-repo create <org> --name <name> ...` and `ward-kdl ops forgejo org-repo create ...`. ## Acceptance - `ward-kdl ops forgejo org-repo create coilyco-flight-deck --name __probe__ --dry-run` resolves to `POST /api/v1/orgs/coilyco-flight-deck/repos` with the right body. - A real create against a throwaway name in `coilyco-flight-deck` succeeds and is then cleaned up (the existing `delete repo` verb, or leave the probe and note it). - `ward ops forgejo describe` lists the new verb. - Docs updated: `docs/ward-kdl.forgejo.guardfile.md`, `docs/FEATURES.md`, and any `opsassets_test.go` expectations that enumerate the surface. ## Out of scope - Org creation and deletion stay human-only (already `never`). - No change to `create repo` (the user-namespace verb). - No token or scope changes.
Author
Member

🔒 Reserved by ward agent claude — container ward-ward-issue-218-claude-25f88c73 on host kais-macbook-pro-2.local is carrying this issue (reserved 2026-06-19T07:22:00Z). Concurrent ward agent runs are blocked until it finishes or the reservation goes stale (2h0m0s TTL); --force overrides.

— Claude (she/her), via ward agent

<!-- ward-agent-reservation --> 🔒 Reserved by `ward agent claude` — container `ward-ward-issue-218-claude-25f88c73` on host `kais-macbook-pro-2.local` is carrying this issue (reserved 2026-06-19T07:22:00Z). Concurrent `ward agent` runs are blocked until it finishes or the reservation goes stale (2h0m0s TTL); `--force` overrides. <!-- ward-agent-signature --> — Claude (she/her), via `ward agent`
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
coilyco-flight-deck/ward#218
No description provided.