Files
Gitea-Tools/docs/llm-workflow-runbooks.md
T

10 KiB

LLM-Operated Gitea Workflow Runbooks

Purpose

Runbooks for the common Gitea workflows an LLM performs through the gitea-mcp package of the MCP Control Plane: creating issues, implementing them, opening and reviewing pull requests, merging, and closing out — safely and reproducibly.

These runbooks are operational guidance only. They add no tooling; the behavior they rely on already exists (canonical runtime profiles, the interactive setup menu, identity/eligibility checks, gated review/merge, and audit logging). See Related documents.

Principle: the profile is the role, not the LLM

The LLM is not the role.
The MCP execution profile used for the task is the role.

An LLM session is never permanently an "author," "reviewer," or "merger." Any session may perform any of these roles — but only while operating through a task-appropriate profile whose authenticated Gitea identity and allowed operations fit the task. A task selects a profile; a profile is not assigned to a model. See gitea-execution-profiles.md.

Example role-scoped instructions:

Use an author profile to implement issue #N and open a PR.
Use any eligible reviewer profile to review PR #N.
Use any eligible merger profile to merge PR #N if checks pass.

Prerequisites: canonical config + thin launchers

Runtime profiles live in one canonical JSON file, referenced by every LLM launcher. No client config contains raw credentials.

Canonical config file

Selected by two environment variables:

  • GITEA_MCP_CONFIG — path to the canonical file (e.g. ~/.config/gitea-tools/profiles.json).
  • GITEA_MCP_PROFILE — the named profile to activate.

Shape (see ../gitea-mcp.example.json):

{
  "version": 1,
  "profiles": {
    "prgs-reviewer": {
      "base_url": "https://gitea.example.invalid",
      "username": "<reviewer-username>",
      "auth": { "type": "keychain", "id": "prgs-reviewer-token" },
      "default_owner": "<owner>",
      "execution_profile": "gitea-reviewer"
    },
    "prgs-author": {
      "base_url": "https://gitea.example.invalid",
      "username": "<author-username>",
      "auth": { "type": "env", "name": "GITEA_TOKEN_PRGS_AUTHOR" },
      "default_owner": "<owner>",
      "execution_profile": "gitea-author"
    }
  }
}
  • version — canonical schema version (currently 1).
  • profiles — map of profile name → profile.
  • auth — a reference, never an inline secret:
    • keychain: { "type": "keychain", "id": "<service-id>" } — the token is read from the macOS keychain on demand.
    • env: { "type": "env", "name": "<ENV_VAR_NAME>" } — the token is read from that environment variable.

Inline token/password keys are rejected. Token values are never stored in, returned by, or logged from profile metadata. Precedence: explicit process env vars override JSON profile values; the JSON profile fills only what the environment leaves unset. With GITEA_MCP_CONFIG unset, behavior is exactly the legacy environment-only mode.

Thin launcher pattern

An LLM MCP launcher (Claude / Gemini / Codex) contains only command, args, and the two GITEA_MCP_* variables — never a token or password:

"gitea-tools": {
  "command": "/path/to/Gitea-Tools/venv/bin/python3",
  "args": ["/path/to/Gitea-Tools/mcp_server.py"],
  "env": {
    "GITEA_MCP_CONFIG": "/path/to/.config/gitea-tools/profiles.json",
    "GITEA_MCP_PROFILE": "prgs-reviewer"
  }
}

Run the same server as several launcher entries (e.g. -author, -reviewer, -merger), each pointing at a different GITEA_MCP_PROFILE.

Setup runbook — interactive menu

Create and manage profiles without hand-editing JSON:

./scripts/gitea-config-menu

Menu options: list / add / edit / remove profiles · validate config · test profile authentication · show authenticated user · generate launcher snippets (Claude/Gemini/Codex) · check reviewer eligibility for a PR.

Create an author + a reviewer profile:

  1. add profile → name prgs-author, base URL, username, default owner/repo, execution profile gitea-author, auth type keychain or env.
    • keychain: store the token now (hidden prompt); it goes to the keychain under an id like prgs-author-token — never into the JSON.
    • env: record a var name like GITEA_TOKEN_PRGS_AUTHOR; set that variable yourself in the environment.
  2. add profile again → name prgs-reviewer, execution profile gitea-reviewer. Existing profiles are preserved.
  3. validate config → confirm no problems.
  4. generate launcher snippets → paste the printed snippet into each LLM client's MCP config (it contains no secret).
  5. test profile authentication → prints the resolved Gitea username (the only time an API call is made, and only on request).
  6. check reviewer eligibility for a PR → enter a PR number; prints the authenticated user, the PR author, and ELIGIBLE / INELIGIBLE. Read-only — it never approves or merges.

Migration runbook — away from duplicated credential blocks

Old setups duplicated GITEA_USER_*, GITEA_PASS_*, and GITEA_SITE_* across every LLM's mcp_config.json — duplicating profiles and exposing secrets.

  1. For each instance/role, create one canonical profile (menu → add profile), storing the secret in the keychain or an env var and referencing it by id/name only.
  2. validate config, then test profile authentication for each profile.
  3. Replace each LLM's server block with the thin launcher (command + args + GITEA_MCP_CONFIG + GITEA_MCP_PROFILE).
  4. Delete the GITEA_USER_* / GITEA_PASS_* / GITEA_SITE_* blocks from every LLM config.
  5. Rotate any token that previously sat in a client config.

Legacy environment-only setups keep working unchanged until migrated.

Workflow runbooks

Each runbook names the profile role it runs under, the steps, and a safe prompt. Confirm the active profile first (gitea_get_profile / gitea_whoami).

Create an issue / child issues

  • Profile: issue-manager or author (any profile allowed to create issues).
  • Steps: create the parent/roadmap issue; create child issues; apply the minimal label set; link children to the parent.
  • Prompt: `Using the issue-manager profile, create issue "