IssueOps

Issue Agent Workflow

Forgejo issues are the operational work queue for this repository. The issue agent workflow is intentionally staged: deterministic code evaluates policy and performs cheap metadata work before any OpenCode run is allowed

Source
docs/issue-agent-workflow.md
Mode
rendered markdown

Issue Agent Workflow

Forgejo issues are the operational work queue for this repository. The issue agent workflow is intentionally staged: deterministic code evaluates policy and performs cheap metadata work before any OpenCode run is allowed. OpenCode uses the shared MoekenIT/agent-skills runtime so CI agents and local agents follow the same skills, agents, commands, and helper conventions.

Design Goals

  • Use labels and issue state as the standing policy for what automation may do.
  • Use slash commands for authorized manual steering and retries.
  • Prefer deterministic checks over model calls when a rule can be encoded in
  • code.

  • Run OpenCode through cheap-orchestrator as the primary CI agent; route
  • specialist work inside that orchestrator instead of invoking subagents directly.

  • Use write-capable orchestration only after policy says the issue is ready.
  • Escalate to frontier review only when labels or gates indicate architecture,
  • security, platform, Confluence, or high-risk implications.

  • Report every gate decision back to the issue and as a workflow artifact.

Stages

1. Intake

Triggered by issues.opened, issues.edited, or /agent classify.

The deterministic evaluator checks whether required label scopes are present: type/*, status/*, priority/*, risk/*, autonomy/*, and delivery/*. When labels are missing, the workflow may add safe default suggestions such as status/triage, priority/p2, risk/medium, autonomy/none, and delivery/comment. Intake does not mutate repository files.

2. Readiness

Triggered by status/ready, approval/agent-ready, agent/readiness, or /agent ready.

Readiness verifies that required label scopes are present and that gate labels have matching approvals. It also requires status/ready; /agent ready checks whether the issue is ready, but it does not silently promote a status/triage issue to ready.

GateRequired Approval
gate/confluence-accessapproval/confluence-access
gate/security-reviewapproval/security-reviewed
gate/platform-reviewapproval/platform-change
gate/human-approvalapproval/agent-ready

If readiness fails, the workflow comments a blocked gate decision. If readiness passes, the issue can proceed to planning, research, review, or implementation depending on labels and commands.

3. Planning And Research

Triggered by agent/plan, agent/research, autonomy/plan, autonomy/comment, /agent plan, or /agent research ....

Planning and research are comment/artifact-only stages. They may inspect the repository and produce a plan, findings, open questions, or proposed labels, but they must not mutate repository files. CI runs still start with cheap-orchestrator; any local research specialist is requested as an internal orchestrator route, not as the primary OpenCode agent.

4. Implementation

Triggered automatically when policy allows or manually by /agent implement, /agent pr, /agent fix, or /agent retry.

Implementation requires:

  • agent/implement
  • approval/agent-ready
  • status/ready for automatic starts
  • a supported delivery label
  • matching autonomy label
  • no unapproved gate labels

Supported delivery policies:

DeliveryRequired LabelsBehavior
delivery/prautonomy/prPlan, implement, validate, push an issue-linked branch, and open or update a PR.
delivery/direct-mainautonomy/direct-main, approval/direct-mainHotfix path only; also requires OPENCODE_DIRECT_MAIN_ENABLED=1.

All implementation runs also require OPENCODE_ISSUE_RUN_ENABLED=1. Without that secret gate, the workflow remains dry-run and records what it would have done.

5. Review

Triggered by agent/review, autonomy/review, or /agent review.

Review is comment/artifact-only by default. It can inspect linked PRs, CI status, issue evidence, and acceptance criteria, then comment findings or requested fixes. Follow-up implementation still goes through the implementation policy gate.

Slash Commands

Commands use the /agent prefix and are accepted only from users listed in workbench/issue-workflow/agent-policies.json under slashCommands.authorizedUsers.

Available commands:

CommandStageNotes
/agent classifyintakeRe-run intake classification and safe label suggestions.
/agent readyreadinessRe-run readiness gates.
/agent planplanningProduce a plan; no repo mutation.
/agent research <scope>researchResearch or inspect and comment findings; no repo mutation.
/agent implementimplementationRun implementation if labels and gates allow it.
/agent primplementationSame as implementation, expecting delivery/pr.
/agent hotfiximplementationRequires direct-main labels and direct-main secret gate.
/agent reviewreviewReview linked PR/evidence and comment findings.
/agent fiximplementationFollow-up implementation after review feedback, still gated.
/agent retryimplementationRetry a failed implementation run, still gated.
/agent stopstopRecords a stop decision; automatic cancellation is not implemented yet.

For direct OpenCode steering, authorized users may also comment /oc:


/oc [--agent <agent-name>] [--write] <prompt>

/oc always starts OpenCode with cheap-orchestrator, because it is the safest general-purpose front door: it can delegate to local specialists and reserve frontier review for high-impact decisions. --agent requests an internal specialist route, such as local-research-analyst for narrow read-only research, local-content-operator for documentation drafting, local-delivery-engineer for scoped implementation/validation, or frontier-decision-reviewer for explicit decision review. Without --write, /oc is comment/artifact-only and must leave the worktree clean. /oc --write from an authorized user is treated as explicit approval for a PR-mode attempt: the workflow applies routine audit labels (status/ready, approval/agent-ready, delivery/pr, and autonomy/pr) automatically and opens or updates an issue-linked PR. Direct-main delivery is intentionally not available through /oc.

Labels remain useful for audit, search, dashboards, and sensitive gates, but they are not a manual prerequisite for the common authorized /oc --write path. Sensitive requests still block until explicit labels/approvals are present, such as Confluence writes, credentialed preview deployment, real RWS content exposure, secret access, or direct-main delivery.

Unauthorized commands are ignored and reported back to the issue.

When a slash command is accepted by the workflow, the first job adds an eyes reaction to the command comment so the requester can see that a runner picked it up before the heavier policy/evaluation job starts. When processing finishes, the workflow adds +1 for completed, gate-passed, or dry-run outcomes and -1 for blocked or failed outcomes. Forgejo's reaction API uses GitHub-compatible reaction names, so these render as the supported reaction icons rather than arbitrary emoji names.

The eyes reaction is still runner-dependent: if all Forgejo runners are busy or the command is waiting in the queue, no workflow code can run yet. The separate acknowledgement job keeps the reaction as early as the current runner pool allows; getting truly immediate acknowledgement would require a webhook/service outside Forgejo Actions.

Policy Files

  • workbench/issue-workflow/labels.json: canonical label taxonomy.
  • workbench/issue-workflow/milestones.json: initial Forgejo milestone
  • containers.

  • workbench/issue-workflow/agent-policies.json: staged automation policy,
  • command allowlist, delivery rules, gate approvals, and frontier-escalation signals.

The deterministic controller is .scripts/evaluate-issue-agent-policy.mjs. It reads the Forgejo event payload, issue labels, actor, comment command, and policy file, then writes:

  • .reports/issue-agent/gate-decision.json
  • .reports/issue-agent/prompt-envelope.json
  • .reports/issue-agent/gate-comment.md

The Forgejo workflow comments the gate result and uploads the full rws-arch-wb-issue-agent artifact.

Gate-only results use gate-passed when policy allows the request without an OpenCode run and gate-blocked when policy stops the request. Blocked implementation gates list only the missing labels or approvals, so a request with agent/implement already present should name approval/agent-ready rather than repeat every required implementation label.

The workflow maintains one rolling issue-agent status comment per issue for gate, blocked, and dry-run outcomes. It looks for the <!-- rws-arch-wb-issue-agent --> marker and updates that comment in place instead of posting a new intake/readiness comment for every event. When a real agent run produces output, the workflow posts a separate result comment marked with <!-- rws-arch-wb-issue-agent-result --> so planning, research, review, and implementation artifacts remain part of the issue history. Result comments stay human-readable: a short outcome sentence, delivery/worktree status, links to the runner and artifact, and an optional collapsed agent note. The full OpenCode transcript is visible in the Forgejo runner log and retained in the short-lived artifact. Forgejo emits label events when template labels are attached, so the workflow ignores non-actionable label events and only continues for status/ready, approval/agent-ready, implementation delivery/autonomy labels, and agent/* labels.

Agent Runtime

When policy requests an OpenCode run, .forgejo/workflows/issue-agent.yml clones https://forge.moeken.eu/MoekenIT/agent-skills.git at AGENT_SKILLS_REF and runs adapters/opencode/install.mjs into an isolated CI config directory. The exact agent-skills commit is written to .reports/issue-agent/agent-skills-runtime.json and included in the issue comment.

Real OpenCode execution requires these repository Actions secrets:

SecretPurpose
OPENCODE_ISSUE_RUN_ENABLEDMust be 1 before any policy-approved OpenCode run starts.
AGENT_SKILLS_TOKENRead token for cloning the private MoekenIT/agent-skills repository. Falls back to ISSUE_WORKFLOW_TOKEN or GITHUB_TOKEN when available.
LITELLM_API_KEYScoped LiteLLM credential used only by the secret-bearing OpenCode step.
LITELLM_BASE_URLOptional LiteLLM endpoint override; defaults to https://llm.moeken.eu/v1.
OPENCODE_DIRECT_MAIN_ENABLEDHotfix-only direct-main gate; leave unset for normal PR/comment testing.

The workflow clones agent-skills with an HTTP authorization header so private cross-repository access does not depend on the current repository token. It then downloads a pinned Linux OpenCode package for the runner architecture, verifies its SHA-1 checksum before execution, disables OpenCode autoupdate in the isolated CI config, and starts OpenCode with the shared cheap-orchestrator profile. The LiteLLM API key is not present in deterministic gate steps; it is injected only after policy, actor allowlist, direct-main, and runtime checks have passed. Issue comments include a bounded, ANSI-stripped, best-effort-redacted final answer or summary instead of a full terminal transcript; the full log is streamed to the runner and retained in the short-lived rws-arch-wb-issue-agent artifact.

For non-mutating stages, the workflow checks git status --porcelain after OpenCode completes. Any remaining repository change fails the run and reports the worktree status, even if the agent command itself returned success.

Some shared agent-skills profiles are intentionally defined as subagents for local orchestration. CI does not invoke those profiles directly; it starts cheap-orchestrator and passes any requested specialist as routing guidance.

For PR-mode write runs, the workflow requires actual repository changes. If OpenCode exits successfully but leaves no changes, the run is marked failed. When changes exist, the workflow commits them to an issue-linked branch, pushes it, opens or updates a pull request against main, and includes the PR URL and changed files in the issue result comment.

Dry-run gate checks do not install agent-skills. The workflow only clones and installs the shared runtime when the policy requests OpenCode and OPENCODE_ISSUE_RUN_ENABLED=1 is configured. Deterministic readiness checks such as /agent ready update the rolling gate comment without model/runtime setup. Dry-run implementation comments report the skipped runtime status instead of an agent-skills commit, because no shared runtime was installed. Comment-only planning, research, and review dry-runs use stage-specific wording so they do not claim to execute implementation work.

The workflow currently uses AGENT_SKILLS_REF=main for fast iteration. Once the workflow stabilizes, pin this value to a tag or commit for reproducibility.

Testing Real Runs

Start with the common command path:

  1. For read-only work, comment /oc <prompt> as an authorized user.
  2. For normal implementation, comment /oc --write <prompt> as an authorized
  3. user; routine PR labels are applied automatically.

  4. Expect an eyes reaction when the runner picks up the command, then a result
  5. comment with the summary, runner link, artifact link, and PR link when one is created.

  6. If the comment says blocked, fix the named sensitive gate, actor, checksum,
  7. or runtime secret before retrying.

  8. Use /agent ... commands only when testing lower-level staged policy behavior
  9. or when an operator needs deterministic gate/readiness checks.

Frontier Escalation

The policy marks these labels as frontier-review signals:

  • risk/high
  • gate/security-review
  • gate/confluence-access
  • gate/platform-review
  • type/decision

The evaluator does not automatically run a frontier model. It records the signal so the selected agent or a human reviewer can route the decision appropriately.

Safety Boundaries

  • Confluence writes, real RWS content exposure, and credentialed preview
  • deployment remain separately approval-gated.

  • Issues must not contain secrets, tokens, Basic Auth hashes, kubeconfig data, or
  • copied private runtime values.

  • delivery/direct-main is scaffolded but blocked unless both labels and
  • OPENCODE_DIRECT_MAIN_ENABLED=1 are present.

  • Label mutation is limited to deterministic intake suggestions; implementation
  • runs should not rewrite labels without a later explicit policy change.