Claude Skill

forgejo-cli

Use when managing a Forgejo or Gitea server from the terminal: issues, pull requests, repositories, file contents, labels, milestones, releases, webhooks, user settings, or any /api/v1 endpoint through a safe generic API command. Do not use this skill for unrelated requests; rout

LLM Mart · 0 points · 10 views 26 listing impressions 0 install-command copies

#code-review #git

Virus-scanned Reviewed automatically before listing.

Full trust report

Download magnus919-agent-skills-forgejo-cli-addad86.zip · 16 KB
Part of magnus919/agent-skills — 145 skills

Install

skills CLI npx skills add https://github.com/magnus919/agent-skills/tree/main/forgejo-cli
Claude Code claude plugin marketplace add https://llmmart.ai/marketplace.json && claude plugin install magnus919-agent-skills@llmmart
Git git clone https://github.com/magnus919/agent-skills.git

The skills CLI installs just this skill, for any of its supported agents. Claude Code installs the whole magnus919/agent-skills collection as a plugin from our marketplace. Git is the plain clone.

README

Forgejo CLI v2 — safe repository automation

Manage a Forgejo server from the terminal without hand-written curl or accidental mutations. It covers daily repository work—issues, pull requests, repositories, contents, metadata, webhooks, and settings—and has a guarded API escape hatch for the rest.

Why Install This Skill

The CLI gives agents one predictable safety contract: JSON is machine-readable, diagnostics stay off stdout, mutations require confirmation, and dry runs never need a token or network access. For version-specific features such as Actions runners and variables, packages, organizations, teams, admin APIs, notifications, and permissions, use the generic API command with your server's Swagger schema.

It deliberately does not try to duplicate every API endpoint. Instead, it offers guarded first-class commands for common repository work and a generic client for the rest. The references explain when to use each, how to select a compatible schema, and how to handle pagination and token scopes.

What You Get

Contents Purpose
scripts/forgejo-cli Argparse Forgejo API v1 client
references/command-reference.md Endpoint and payload guide
references/api-usage.md Authentication, pagination, versioning, and schema-discovery procedure
references/endpoint-routing.md Decision guide for first-class commands versus generic API calls
references/troubleshooting.md Safe diagnosis of API and transport failures
V2-SPEC.md v2 acceptance criteria
tests/ Offline stdlib contract tests

Quick Start

Set FORGEJO_AGENT_TOKEN (default) or FORGEJO_USER_TOKEN, then run:

python3 scripts/forgejo-cli --dry-run --json repo create --name demo --private
python3 scripts/forgejo-cli --server https://forge.example api --method GET --path /api/v1/user --json
python3 scripts/forgejo-cli --server https://forge.example --page 1 --limit 50 --include-response issue list --owner acme --repo app --json

Triggers

  • Managing Forgejo/Gitea issues, PRs, repos, file contents, releases, or hooks.
  • Calling a version-specific /api/v1/ endpoint safely.
  • Previewing a Forgejo mutation.

Requirements

Python 3.8+ and requests for live API calls. --help and --dry-run need no token or dependency. Set FORGEJO_AGENT_TOKEN or FORGEJO_USER_TOKEN for token authentication. A deliberate Authorization header supports other documented schemes, but avoid putting secrets directly in shell history. Consult your Forgejo server's /api/swagger or /swagger.v1.json for exact schemas.

Skill manifest

Forgejo CLI v2

Run python3 scripts/forgejo-cli. --agent (default) uses FORGEJO_AGENT_TOKEN; --user uses FORGEJO_USER_TOKEN; --server URL selects an installation. Set FORGEJO_SERVER in your shell if your wrapper supplies it, otherwise pass --server explicitly.

Safety

  • Mutations require --force/--yes/-y, or --dry-run.
  • --dry-run --json emits one plan with method, path, query, and body; it makes no network request.
  • --json writes exactly one JSON value to stdout; diagnostics go to stderr.
  • --page and --limit work for any list/search request. Add --include-response to receive the HTTP status plus link and x-total-count pagination headers.
  • --help does not read credentials or contact a server. Path segments are encoded.

Common workflows

python3 scripts/forgejo-cli issue list --owner acme --repo app --json
python3 scripts/forgejo-cli --dry-run --json repo create --name demo --private
python3 scripts/forgejo-cli --dry-run --json api --method POST \
  --path /api/v1/repos/acme/app/actions/variables --data '{"name":"KEY","value":"value"}'

First-class groups: issue, pr, repo, content, label, milestone, release, hook, and user. content expects base64 and update/delete require the current SHA. Use api for any other /api/v1/ endpoint; it supports JSON, raw files, multipart uploads/forms, and custom headers. Consult /api/swagger or /swagger.v1.json on the selected server. See command reference.

Choosing a command

Use a first-class command for its covered daily workflow. Use api when the operation is absent, requires version-specific fields, or needs a schema not represented by a simple flag. Before using api, read endpoint routing; read API usage for authentication, pagination, compatibility, and safe schema discovery. Read troubleshooting for 401/403/422 responses and transport failures.

Files (agent-skills)
  • evals
    • evals.json 2.8 KB
      {
        "schema_version": 1,
        "skill_name": "forgejo-cli",
        "evals": [
          {
            "id": "forgejo-cli-core-workflow",
            "prompt": "Use forgejo cli to handle a realistic primary task. Explain the inputs, ordered workflow, and concrete output.",
            "expected_output": "A forgejo cli response defines the task boundary, identifies required inputs, applies the documented workflow, and produces a concrete output with verification.",
            "assertions": [
              "Names the forgejo cli task and required inputs",
              "Applies an ordered workflow rather than generic advice",
              "Produces a concrete output and verification step"
            ]
          },
          {
            "id": "forgejo-cli-failure-diagnosis",
            "prompt": "A forgejo cli task is failing with an ambiguous symptom. Diagnose it and give a bounded recovery path.",
            "expected_output": "The response separates symptoms from causes, proposes evidence-gathering checks, and gives a reversible recovery path with a stop condition.",
            "assertions": [
              "Separates symptom, hypothesis, and evidence",
              "Uses targeted diagnostic checks",
              "Includes a reversible recovery and stop condition"
            ]
          },
          {
            "id": "forgejo-cli-safety-boundary",
            "prompt": "Plan a forgejo cli change that could affect user data or external state. Show the safety gate before acting.",
            "expected_output": "The response confirms scope and authority, defaults to read-only or dry-run inspection, and requires explicit confirmation before consequential mutation.",
            "assertions": [
              "Confirms target, scope, and authority before mutation",
              "Uses read-only or dry-run inspection first",
              "Requires explicit confirmation for consequential changes"
            ]
          },
          {
            "id": "forgejo-cli-edge-case",
            "prompt": "Apply forgejo cli when requirements conflict or an important input is missing. Decide what to do next.",
            "expected_output": "The response identifies the missing or conflicting constraint, refuses to invent facts, and escalates or requests the smallest clarifying input needed.",
            "assertions": [
              "Identifies the missing or conflicting constraint",
              "Does not invent unavailable facts",
              "Requests clarification or escalates with a bounded next step"
            ]
          },
          {
            "id": "forgejo-cli-evidence-handoff",
            "prompt": "Create a review-ready forgejo cli handoff for another practitioner.",
            "expected_output": "The handoff records assumptions, decisions, artifacts, validation evidence, and unresolved risks so another practitioner can reproduce the result.",
            "assertions": [
              "Records assumptions and decisions",
              "Links concrete artifacts to validation evidence",
              "States unresolved risks and reproducible next steps"
            ]
          }
        ]
      }
      
  • references
    • api-usage.md 2 KB
      # API usage, compatibility, and pagination
      
      ## Establish the server contract
      
      1. Pass the target with `--server https://forge.example`; do not treat the placeholder default as a usable service.
      2. Request `GET /api/v1/version` with the generic command and record the Forgejo major version.
      3. Open `https://forge.example/swagger.v1.json` (or `/api/swagger`) and use that server's schema for request fields. Forgejo guarantees API compatibility within a major version; do not assume a current server has the same endpoints or fields as an older Gitea-compatible installation. The upstream usage guide is https://forgejo.org/docs/latest/user/api-usage/.
      
      ## Authenticate safely
      
      Use `FORGEJO_AGENT_TOKEN` for automation and `FORGEJO_USER_TOKEN` for user-authorized work. Give tokens the narrowest Forgejo scope that can complete the request. The client sends these as `Authorization: token …`.
      
      The generic `--header Authorization=…` path supports Basic or Bearer authentication when an endpoint requires it. Prefer an environment-backed wrapper or a token for routine use: command-line credentials may be recorded in shell history and process listings. Never put tokens in `--data`, dry-run output, issue text, or logs.
      
      ## Paginate intentionally
      
      All list/search commands accept `--page N --limit N`, including generic API calls. Use `--include-response --json` on a live request to retain Forgejo's `link` and `x-total-count` headers:
      
      ```bash
      python3 scripts/forgejo-cli --server https://forge.example --page 1 --limit 50 \
        --include-response --json issue list --owner acme --repo app
      ```
      
      Follow the `rel="next"` URL until absent. Do not assume a fixed page size: server administrators configure defaults and maximum response items.
      
      ## Scope boundaries
      
      The generic `api` command intentionally accepts only `/api/v1/` paths. Package registries and other non-v1 endpoints require their native client or a separately reviewed HTTP workflow. First-class commands provide guardrails; the generic command provides coverage, not schema validation.
      
    • command-reference.md 3.8 KB
      # Command reference
      
      Global flags: `--agent`, `--user`, `--server URL`, `--json`, `--quiet/-q`, `--verbose/-v`, `--dry-run/-n`, `--force/--yes/-y`, `--page`, `--limit`, and `--include-response`. POST, PUT, PATCH, and DELETE require `--force` unless dry-running. `--page` and `--limit` are appended as query parameters; `--include-response` wraps live output as `{data, status, headers}` and preserves `link` and `x-total-count`.
      
      | Group | Commands | API route |
      | --- | --- | --- |
      | `issue` | list, show, create, edit, close, reopen, assign, labels, set-labels, add-labels, clear-labels, comments, comment, delete-comment | `/repos/{owner}/{repo}/issues` |
      | `pr` | list, show, create, edit, diff, comment, reviews, review, merge | `/repos/{owner}/{repo}/pulls` |
      | `repo` | list, show, search, create, edit, delete, branches | `/user/repos`, `/repos`, `/repos/search` |
      | `content` | get, create, update, delete | `/repos/{owner}/{repo}/contents/{path}` |
      | `label`, `milestone` | list, show, create, edit, delete | matching repository metadata collection |
      | `release` | list, show, create, edit, delete, assets, upload | `/repos/{owner}/{repo}/releases` |
      | `hook` | list, show, create, edit, delete | `/user/hooks` or `/repos/{owner}/{repo}/hooks` |
      | `user` | show, settings, update-settings | `/user`, `/user/settings` |
      
      Comma-separated `--labels`, `--assignees`, and `--events` become JSON arrays. PR merge maps `--style` to Forgejo's `Do` field. Hook create accepts `--url`, `--secret`, `--events`, and `--type`; it builds Forgejo's required nested `config` payload. Release create requires `--tag-name`; its display name is `--name`. Content is base64 in `--content`; update and delete require `--sha`.
      
      ## First-class command details
      
      - `issue list` and `pr list` default to `--state open`; override it when reviewing closed or all work. `issue close` and `issue reopen` use the same edit endpoint with an explicit state.
      - `content --path` preserves directory separators and encodes unsafe characters. Supply base64 data to `--content`, not plain text. Fetch the current file SHA before an update or delete to avoid overwriting a newer version.
      - `repo list --owner OWNER` lists that owner's public/visible repositories; without `--owner`, it lists the authenticated user's repositories. `repo create` intentionally requires no owner because it creates under the authenticated user.
      - `release upload --file PATH` sends a multipart attachment. `release upload --external-url URL` sends the equivalent form field. They are mutually exclusive.
      - `hook` operates on repository hooks when both `--owner` and `--repo` are present, otherwise on the authenticated user's hooks. Hook creation requires `--url`.
      
      ## Safe examples
      
      ```bash
      # See the exact update request before changing a file.
      python3 scripts/forgejo-cli --dry-run --json content update \
        --owner acme --repo app --path docs/guide.md --content BASE64 --sha CURRENT_SHA
      
      # Obtain pagination links and a total count from a live list request.
      python3 scripts/forgejo-cli --server https://forge.example --page 1 --limit 50 \
        --include-response --json pr list --owner acme --repo app
      ```
      
      ## Generic API
      
      `forgejo-cli api --method GET|POST|PUT|PATCH|DELETE --path /api/v1/... [--query KEY=VALUE] [--data JSON | --data-file FILE] [--raw-file FILE] [--upload-file FILE --form KEY=VALUE] [--header KEY=VALUE] [--content-type TYPE]`
      
      Only `/api/v1/` paths are accepted. JSON, raw binary, multipart file/form payloads, and custom headers are supported. A supplied `Authorization` header is accepted when no token environment variable is set, enabling documented Basic or Bearer authentication; avoid putting credentials in shell history. Use it for Actions, packages, organizations, teams, admin APIs, notifications, repository permissions, and new endpoints; consult the target server's Swagger document for schemas.
      
    • endpoint-routing.md 1.3 KB
      # Endpoint routing guide
      
      Use the first-class command when it exposes every field needed by the task. It gives semantic flags, safe path encoding, mutation confirmation, and predictable JSON output.
      
      | Task | Default command | Use `api` instead when |
      | --- | --- | --- |
      | Issues and comments | `issue` | attachments, reactions, dependencies, time tracking, or a schema field not exposed by flags |
      | Pull requests | `pr` | commits/files/statuses, reviewers beyond the basic review call, or version-specific merge fields |
      | Repository and files | `repo`, `content` | collaborators, branch/tag protection, keys, mirrors, transfer, archive, or advanced settings |
      | Metadata and delivery | `label`, `milestone`, `release`, `hook` | a payload needs fields not represented by the first-class command |
      | Account settings | `user` | tokens, notifications, subscriptions, SSH/GPG keys, organizations, teams, or admin operations |
      | Actions, packages, projects | `api` | always: these APIs evolve independently and need the live Swagger schema or native package client |
      
      For a generic call, first read the target server's Swagger operation, copy its method and required fields exactly, then dry-run the request. Add `--force` only after reviewing the plan. If the endpoint returns a list, include `--page`, `--limit`, and `--include-response`.
      
    • troubleshooting.md 1.4 KB
      # Troubleshooting Forgejo API calls
      
      | Symptom | Check | Safe next action |
      | --- | --- | --- |
      | `No API token available` | Required environment variable is absent | Export the intended token or provide a deliberate `Authorization` header for the one request |
      | 401 | Token type, expiry, server URL, or authentication scheme | Run a read-only `user show`; do not retry mutations blindly |
      | 403 | Token scope, repository access, or server policy | Inspect the target endpoint's required scope and permissions; use a narrower correctly scoped token rather than escalating indiscriminately |
      | 404 | Owner/repo/path or server-version mismatch | Check `/api/v1/version` and the server's Swagger document before changing the path |
      | 422 | Valid route but invalid payload | Compare the complete JSON body against the live Swagger schema; dry-run first-class calls to inspect generated fields |
      | Missing list results | Pagination | Add `--page`, `--limit`, and `--include-response`; follow the `link` header |
      | Connection error | DNS, TLS, proxy, or server availability | Verify the exact `--server` URL with a harmless version request; do not expose tokens in diagnostic output |
      
      Use `--verbose` only to inspect method and URL. It deliberately does not print tokens or request bodies. For mutation failures, retain the dry-run JSON plan and the status/message, but redact credentials before sharing either.
      
  • scripts
    • forgejo-cli 21.3 KB · in bundle
  • tests
    • test_cli.py 5.5 KB
      import importlib.machinery
      import io
      import json
      import pathlib
      from types import SimpleNamespace
      import unittest
      from contextlib import redirect_stderr, redirect_stdout
      
      SCRIPT = pathlib.Path(__file__).parents[1] / "scripts" / "forgejo-cli"
      cli = importlib.machinery.SourceFileLoader("forgejo_cli", str(SCRIPT)).load_module()
      
      
      class CliTests(unittest.TestCase):
          def run_cli(self, args):
              out, err = io.StringIO(), io.StringIO()
              with redirect_stdout(out), redirect_stderr(err):
                  try:
                      cli.main(args)
                  except SystemExit as exc:
                      return exc.code, out.getvalue(), err.getvalue()
              return 0, out.getvalue(), err.getvalue()
      
          def plan(self, args):
              code, out, err = self.run_cli(["--dry-run", "--json"] + args)
              self.assertEqual(code, 0, err)
              return json.loads(out)
      
          def test_help_needs_no_credentials(self):
              self.assertEqual(self.run_cli(["--help"])[0], 0)
              self.assertEqual(self.run_cli(["issue", "--help"])[0], 0)
      
          def test_issue_create_plan(self):
              plan = self.plan(["issue", "create", "--owner", "me", "--repo", "x", "--title", "hello"])
              self.assertEqual((plan["method"], plan["path"]), ("POST", "/api/v1/repos/me/x/issues"))
              self.assertEqual(plan["body"]["title"], "hello")
      
          def test_mutation_requires_force(self):
              code, _, err = self.run_cli(["repo", "create", "--name", "x"])
              self.assertNotEqual(code, 0)
              self.assertIn("mutation", err)
      
          def test_live_request_requires_a_server(self):
              old = cli.DEFAULT_SERVER
              cli.DEFAULT_SERVER = ""
              try:
                  code, _, err = self.run_cli(["user", "show"])
              finally:
                  cli.DEFAULT_SERVER = old
              self.assertNotEqual(code, 0)
              self.assertIn("No Forgejo server selected", err)
      
          def test_api_path_guard_and_plan(self):
              self.assertNotEqual(self.run_cli(["api", "--method", "GET", "--path", "/bad"])[0], 0)
              plan = self.plan(["api", "--method", "PATCH", "--path", "/api/v1/user/settings", "--query", "theme=dark", "--data", '{"language":"en"}'])
              self.assertEqual(plan["query"], {"theme": "dark"})
              self.assertEqual(plan["body"], {"language": "en"})
      
          def test_representative_groups(self):
              cases = [
                  (["pr", "create", "--owner", "me", "--repo", "x", "--title", "t", "--head", "h", "--base", "main"], "POST", "/api/v1/repos/me/x/pulls"),
                  (["release", "create", "--owner", "me", "--repo", "x", "--tag-name", "v2"], "POST", "/api/v1/repos/me/x/releases"),
                  (["content", "update", "--owner", "me", "--repo", "x", "--path", "a b.txt", "--content", "eA==", "--sha", "abc"], "PUT", "/api/v1/repos/me/x/contents/a%20b.txt"),
                  (["hook", "create", "--owner", "me", "--repo", "x", "--url", "https://hook"], "POST", "/api/v1/repos/me/x/hooks"),
              ]
              for args, method, path in cases:
                  plan = self.plan(args)
                  self.assertEqual((plan["method"], plan["path"]), (method, path))
      
          def test_merge_hook_and_release_payloads(self):
              merge = self.plan(["pr", "merge", "--owner", "me", "--repo", "x", "--index", "1", "--style", "squash"])
              self.assertEqual(merge["body"], {"Do": "squash"})
              hook = self.plan(["hook", "create", "--owner", "me", "--repo", "x", "--url", "https://hook", "--events", "push"])
              self.assertEqual(hook["body"]["config"]["url"], "https://hook")
              self.assertEqual(hook["body"]["type"], "forgejo")
              release = self.plan(["release", "create", "--owner", "me", "--repo", "x", "--tag-name", "v2", "--name", "Version 2"])
              self.assertEqual(release["body"], {"tag_name": "v2", "name": "Version 2"})
      
          def test_repo_creation_needs_no_owner(self):
              self.assertEqual(self.plan(["repo", "create", "--name", "demo", "--private"])["path"], "/api/v1/user/repos")
      
          def test_nested_content_path_and_pagination_plan(self):
              plan = self.plan(["--page", "2", "--limit", "75", "content", "get", "--owner", "me", "--repo", "x", "--path", "dir/a b.txt"])
              self.assertEqual(plan["path"], "/api/v1/repos/me/x/contents/dir/a%20b.txt")
              self.assertEqual(plan["query"], {"page": 2, "limit": 75})
      
          def test_form_transport_custom_authorization_and_response_metadata(self):
              class Response:
                  status_code = 200
                  content = b'{"ok":true}'
                  text = '{"ok":true}'
                  headers = {"Link": '<https://forge.example/api/v1/user/repos?page=2>; rel="next"', "X-Total-Count": "51"}
      
                  def json(self):
                      return {"ok": True}
      
              class Requests:
                  RequestException = Exception
                  call = None
      
                  @classmethod
                  def request(cls, *args, **kwargs):
                      cls.call = (args, kwargs)
                      return Response()
      
              original = cli.requests
              cli.requests = Requests
              try:
                  args = SimpleNamespace(server="https://forge.example", dry_run=False, verbose=False, user=False)
                  result = cli.Client(args).request(
                      "POST", "/api/v1/repos/me/x/releases/1/assets", headers={"Authorization": "Basic test"},
                      form={"external_url": "https://example.invalid/file"}, include_response=True)
              finally:
                  cli.requests = original
              self.assertEqual(Requests.call[1]["data"], {"external_url": "https://example.invalid/file"})
              self.assertEqual(result["data"], {"ok": True})
              self.assertEqual(result["headers"]["x-total-count"], "51")
      
      
      if __name__ == "__main__":
          unittest.main()
      
  • README.md 2.5 KB
    # Forgejo CLI v2 — safe repository automation
    
    Manage a Forgejo server from the terminal without hand-written `curl` or accidental mutations. It covers daily repository work—issues, pull requests, repositories, contents, metadata, webhooks, and settings—and has a guarded API escape hatch for the rest.
    
    ## Why Install This Skill
    
    The CLI gives agents one predictable safety contract: JSON is machine-readable, diagnostics stay off stdout, mutations require confirmation, and dry runs never need a token or network access. For version-specific features such as Actions runners and variables, packages, organizations, teams, admin APIs, notifications, and permissions, use the generic API command with your server's Swagger schema.
    
    It deliberately does not try to duplicate every API endpoint. Instead, it offers guarded first-class commands for common repository work and a generic client for the rest. The references explain when to use each, how to select a compatible schema, and how to handle pagination and token scopes.
    
    ## What You Get
    
    | Contents | Purpose |
    | --- | --- |
    | `scripts/forgejo-cli` | Argparse Forgejo API v1 client |
    | `references/command-reference.md` | Endpoint and payload guide |
    | `references/api-usage.md` | Authentication, pagination, versioning, and schema-discovery procedure |
    | `references/endpoint-routing.md` | Decision guide for first-class commands versus generic API calls |
    | `references/troubleshooting.md` | Safe diagnosis of API and transport failures |
    | `V2-SPEC.md` | v2 acceptance criteria |
    | `tests/` | Offline stdlib contract tests |
    
    ## Quick Start
    
    Set `FORGEJO_AGENT_TOKEN` (default) or `FORGEJO_USER_TOKEN`, then run:
    
    ```bash
    python3 scripts/forgejo-cli --dry-run --json repo create --name demo --private
    python3 scripts/forgejo-cli --server https://forge.example api --method GET --path /api/v1/user --json
    python3 scripts/forgejo-cli --server https://forge.example --page 1 --limit 50 --include-response issue list --owner acme --repo app --json
    ```
    
    ## Triggers
    
    - Managing Forgejo/Gitea issues, PRs, repos, file contents, releases, or hooks.
    - Calling a version-specific `/api/v1/` endpoint safely.
    - Previewing a Forgejo mutation.
    
    ## Requirements
    
    Python 3.8+ and `requests` for live API calls. `--help` and `--dry-run` need no token or dependency. Set `FORGEJO_AGENT_TOKEN` or `FORGEJO_USER_TOKEN` for token authentication. A deliberate `Authorization` header supports other documented schemes, but avoid putting secrets directly in shell history. Consult your Forgejo server's `/api/swagger` or `/swagger.v1.json` for exact schemas.
    
  • SKILL.md 2.5 KB
    ---
    name: forgejo-cli
    description: >-
      Use when managing a Forgejo or Gitea server from the terminal: issues, pull requests,
      repositories, file contents, labels, milestones, releases, webhooks, user settings, or
      any /api/v1 endpoint through a safe generic API command. Do not use this skill for
      unrelated requests; route to the nearest named specialist.
    license: MIT
    compatibility: Python 3.8+; requests is required only for live API calls.
    metadata:
      version: 2.0.0
      tags: forgejo, gitea, git, api, code-review
    ---
    
    # Forgejo CLI v2
    
    Run `python3 scripts/forgejo-cli`. `--agent` (default) uses `FORGEJO_AGENT_TOKEN`; `--user` uses `FORGEJO_USER_TOKEN`; `--server URL` selects an installation. Set `FORGEJO_SERVER` in your shell if your wrapper supplies it, otherwise pass `--server` explicitly.
    
    ## Safety
    
    - Mutations require `--force`/`--yes`/`-y`, or `--dry-run`.
    - `--dry-run --json` emits one plan with `method`, `path`, `query`, and `body`; it makes no network request.
    - `--json` writes exactly one JSON value to stdout; diagnostics go to stderr.
    - `--page` and `--limit` work for any list/search request. Add `--include-response` to receive the HTTP status plus `link` and `x-total-count` pagination headers.
    - `--help` does not read credentials or contact a server. Path segments are encoded.
    
    ## Common workflows
    
    ```bash
    python3 scripts/forgejo-cli issue list --owner acme --repo app --json
    python3 scripts/forgejo-cli --dry-run --json repo create --name demo --private
    python3 scripts/forgejo-cli --dry-run --json api --method POST \
      --path /api/v1/repos/acme/app/actions/variables --data '{"name":"KEY","value":"value"}'
    ```
    
    First-class groups: `issue`, `pr`, `repo`, `content`, `label`, `milestone`, `release`, `hook`, and `user`. `content` expects base64 and update/delete require the current SHA. Use `api` for any other `/api/v1/` endpoint; it supports JSON, raw files, multipart uploads/forms, and custom headers. Consult `/api/swagger` or `/swagger.v1.json` on the selected server. See [command reference](references/command-reference.md).
    
    ## Choosing a command
    
    Use a first-class command for its covered daily workflow. Use `api` when the operation is absent, requires version-specific fields, or needs a schema not represented by a simple flag. Before using `api`, read [endpoint routing](references/endpoint-routing.md); read [API usage](references/api-usage.md) for authentication, pagination, compatibility, and safe schema discovery. Read [troubleshooting](references/troubleshooting.md) for 401/403/422 responses and transport failures.
    
  • V2-SPEC.md 819 B
    # Forgejo CLI v2 implementation specification
    
    Provide polished collaboration and repository commands plus a safe generic `/api/v1/` escape hatch. The CLI must require confirmation for mutations, produce credential-free dry-run plans, encode path segments, and keep JSON stdout machine-readable.
    
    Acceptance: tests verify help, mutation gating, generic path validation, JSON plans, repository creation without owner/repo, and representative issue, PR, release, content, and webhook requests. Live transport tests must cover multipart or form delivery, caller-provided authentication, response pagination metadata, missing-server failure, and nested content paths. Documentation must explain version-aware Swagger discovery, scope-aware authentication, pagination, and when a generic endpoint is the appropriate choice.
    

Comments (0)

Sign in to join the conversation.

No comments yet.

Reviews (0)

No reviews yet.

Related