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
- Run OpenCode through
cheap-orchestratoras the primary CI agent; route - Use write-capable orchestration only after policy says the issue is ready.
- Escalate to frontier review only when labels or gates indicate architecture,
- Report every gate decision back to the issue and as a workflow artifact.
code.
specialist work inside that orchestrator instead of invoking subagents directly.
security, platform, Confluence, or high-risk implications.
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.
| Gate | Required Approval |
|---|---|
gate/confluence-access | approval/confluence-access |
gate/security-review | approval/security-reviewed |
gate/platform-review | approval/platform-change |
gate/human-approval | approval/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/implementapproval/agent-readystatus/readyfor automatic starts- a supported delivery label
- matching autonomy label
- no unapproved gate labels
Supported delivery policies:
| Delivery | Required Labels | Behavior |
|---|---|---|
delivery/pr | autonomy/pr | Plan, implement, validate, push an issue-linked branch, and open or update a PR. |
delivery/direct-main | autonomy/direct-main, approval/direct-main | Hotfix 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:
| Command | Stage | Notes |
|---|---|---|
/agent classify | intake | Re-run intake classification and safe label suggestions. |
/agent ready | readiness | Re-run readiness gates. |
/agent plan | planning | Produce a plan; no repo mutation. |
/agent research <scope> | research | Research or inspect and comment findings; no repo mutation. |
/agent implement | implementation | Run implementation if labels and gates allow it. |
/agent pr | implementation | Same as implementation, expecting delivery/pr. |
/agent hotfix | implementation | Requires direct-main labels and direct-main secret gate. |
/agent review | review | Review linked PR/evidence and comment findings. |
/agent fix | implementation | Follow-up implementation after review feedback, still gated. |
/agent retry | implementation | Retry a failed implementation run, still gated. |
/agent stop | stop | Records 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 milestoneworkbench/issue-workflow/agent-policies.json: staged automation policy,
containers.
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:
| Secret | Purpose |
|---|---|
OPENCODE_ISSUE_RUN_ENABLED | Must be 1 before any policy-approved OpenCode run starts. |
AGENT_SKILLS_TOKEN | Read token for cloning the private MoekenIT/agent-skills repository. Falls back to ISSUE_WORKFLOW_TOKEN or GITHUB_TOKEN when available. |
LITELLM_API_KEY | Scoped LiteLLM credential used only by the secret-bearing OpenCode step. |
LITELLM_BASE_URL | Optional LiteLLM endpoint override; defaults to https://llm.moeken.eu/v1. |
OPENCODE_DIRECT_MAIN_ENABLED | Hotfix-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:
- For read-only work, comment
/oc <prompt>as an authorized user. - For normal implementation, comment
/oc --write <prompt>as an authorized - Expect an
eyesreaction when the runner picks up the command, then a result - If the comment says
blocked, fix the named sensitive gate, actor, checksum, - Use
/agent ...commands only when testing lower-level staged policy behavior
user; routine PR labels are applied automatically.
comment with the summary, runner link, artifact link, and PR link when one is created.
or runtime secret before retrying.
or when an operator needs deterministic gate/readiness checks.
Frontier Escalation
The policy marks these labels as frontier-review signals:
risk/highgate/security-reviewgate/confluence-accessgate/platform-reviewtype/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
- Issues must not contain secrets, tokens, Basic Auth hashes, kubeconfig data, or
delivery/direct-mainis scaffolded but blocked unless both labels and- Label mutation is limited to deterministic intake suggestions; implementation
deployment remain separately approval-gated.
copied private runtime values.
OPENCODE_DIRECT_MAIN_ENABLED=1 are present.
runs should not rewrite labels without a later explicit policy change.