Mentioning a dev agent no longer spawns a branch + PR machinery. It is a
CONVERSATION by default: the dev reads what it needs and replies in-thread.
- route.sh: workmode=build|discuss for mode=pr agents. Build ONLY on the
explicit signals: PR-thread comments (resume), the pm delegation template
("please proceed with issue …" — a human can write it too), or the qa bounce
("please address my review …"). Everything else = discuss: no branch prep,
no "🔨 Building" notice.
- run-agent.sh: discussion ACTION for devs (read-only consult, no edits/
commits/markers). @pm gains 'ASK: @<dev> <question>' to consult devs before
planning — gather feasibility/effort input, then DELEGATE when enough is
known. One ASK per reply; never ASK+DELEGATE together.
- publish.sh: pm ASK handler posts the question as a discussion trigger; dev
discuss path posts the reply (+run report) and skips ALL git/PR machinery
(stray edits discarded). ASK marker stripped from visible replies.
- agent.yml: WORKMODE threaded to Run-agent + Publish. README documents it.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- publish.sh: resolve_prs matches ai/issue-N AND ai/issue-N-<slug> split branches
(exact-only silently stalled DELEGATE:@qa and autopilot MERGE_PR on slugged
work); qa hand-off lists all open PRs; autopilot refuses to merge multi-PR
issues (drops the label, hands to the human) — merging one of several open
PRs is half a change deployed. Retro's state=all resolve matches slugs too.
- fetch-thread.sh: paginate and keep the NEWEST 100 comments — a bare limit=100
kept the OLDEST page and dropped recent decisions on long threads.
- route.sh: word-boundary mention matching ("@internal" no longer routes to
@intern); a comment with no real agent mention now SKIPS gracefully
(mode=skip outputs + step guards in agent.yml) instead of a red run.
- run-agent.sh: LEARNINGS.md cap is line-aware and keeps the NEWEST entries
(retros append at the bottom; the old head -c cut the latest lessons first).
- agents.json/README: @pm gemma4 -> minimax-m3 — the retro rule demands an
investigating PM, and gemma4 posted 0 tool calls on every run; minimax is the
model @qa demonstrably uses tools with.
- agent.yml: document the PR-thread concurrency-group caveat.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
New learning step: ask @pm for a retrospective on any issue and the system
turns what happened into prompt-visible rules for future runs.
- run-agent.sh: @pm gains a RETRO marker (emit only when the maintainer asks);
LEARNINGS.md (caller repo root, capped at 4KB) is injected into EVERY agent's
prompt as "TEAM LEARNINGS" — the feedback loop that makes delegation more
robust over time.
- publish.sh: on @pm's RETRO marker, open a "retro: issue #N" issue pointing at
the issue + its PR (state=all resolve, works after merge) and trigger @senior
on it (has gitea-api to read both threads). The retro produces a LEARNINGS.md
PR through the NORMAL choreography (senior → pm → qa), so retros are reviewed
like any change. Strip the RETRO marker from visible replies.
- publish.sh: bounce counter now counts only @qa-authored comments matching the
exact trigger template — on PR #84 it jumped 1/3 → 3/3 because a qa review
QUOTED our own "(fix attempt …)" template from the diff, halving the fix
budget. Template + regex pinned together with a sync note.
- README: document the retro loop.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Fixes from a full repo review:
- fetch-thread.sh: attribute every comment to its REAL author (@pm/@qa/… —
agents post as their own users now); the old "🤖 @name line at the top" hint
pointed at headers we removed, leaving every teammate comment anonymous. Also
strip the hidden loop-prevention marker from bodies (prompt noise).
- agent.yml: per-issue concurrency group (queued, no cancel) — two quick
comments on one issue no longer race the same ai/issue-N branch.
- rescue-pr.sh: after opening a rescue PR, hand it back into the flow with an
unmarked @pm trigger (the pm→qa choreography previously stalled silently on
any rescued run); drop the old "🤖 **@name**" header style; add ops to the
token case; mark the status note with the hidden marker.
- README: token table said "@qa merges / TOKEN_QA needs write:repository" —
inverted since the PM-orchestrated flow (@pm merges, autopilot only; @qa is
read-only). Updated the agent table (descs, node1-ssh moved to homelab) and
added a "How a task flows" section.
- agents.json: pm/qa descs now describe the orchestrator/reviewer roles (these
feed the roster prompt agents route by).
- NEW ci.yml: bash -n + shellcheck(-S error) on every script, YAML-parse on
every workflow, agents.json schema check — the ${x:-{}} brace bug would have
been caught here before it shipped.
- install-opencode.sh: pin opencode (default 1.17.13, override via
OPENCODE_VERSION) — a breaking release no longer takes down every agent.
- build-activity-log.sh: ollama/ollama-cloud models are subscription-billed
(no $/token exists) — label the footer "subscription" instead of a
misleading $0.0000; metered (anthropic) models keep the real dollar cost.
- route.sh: document that mention-priority is list-order and load-bearing for
the flow's trigger comments.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
All three consuming repos (gitea/agents, gitea/ops, ffaerber/homelab) now
carry the per-agent TOKEN_* secrets (org-level for gitea/*, user-level for
ffaerber/*), so the shared AGENT_TOKEN fallback is no longer needed.
- agent.yml: SELF_TOKEN ternary ends in '' instead of secrets.AGENT_TOKEN;
removed AGENT_TOKEN from the publish + rescue step env.
- publish.sh: TTOK is just the agent's own token; if an agent somehow has none
(TOK fell back to the built-in GT), TTOK is left empty so the trigger/merge
is skipped rather than silently no-op'ing under the built-in token.
- README: drop the AGENT_TOKEN row; state that every consuming repo must carry
the per-agent TOKEN_* (no shared fallback).
The AGENT_TOKEN Actions secrets (org + user) and its gitea/secrets/.env entry
are removed separately.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The secret table still described AGENT_TOKEN as primary and TOKEN_* as
optional "falls back to the bot". The per-agent-token refactor inverted that:
each agent's own TOKEN_* is primary (selected into SELF_TOKEN), AGENT_TOKEN is
now only the fallback for repos without per-agent tokens. Document TOKEN_OPS,
the SELF_TOKEN selection, and that TOKEN_QA needs write:repository to merge.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Repo transferred ffaerber/agents -> gitea/agents. Point the scripts checkout (agent.yml
repository:), the standard caller (uses:), and the README at gitea/agents. The trigger gate still
keys on the maintainer 'ffaerber' (unchanged).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
A comment-mode operator agent (opus) for administering Gitea itself from issues in gitea/ops:
create orgs/users/repos, manage labels & Actions secrets, and mint least-privilege per-user tokens.
- agents.json: new @ops role (comment-mode, skill gitea-admin, confirms before destructive ops).
- skill-gitea-admin.sh: SKILL.md documenting org/user/repo/label/secret ops + the create-user →
mint-scoped-token → store-as-secret flow (never printing tokens). Gated on NAME=ops so the admin
how-to is written ONLY for @ops; permission.skill also denies it to other agents.
- agent.yml: wire the skill step (uses AGENT_TOKEN — an admin PAT during bootstrap).
Bootstrap note: AGENT_TOKEN is admin for now, so every agent's process technically holds an admin
credential (skill-scoping hides the doc, not the env var). Once @ops is minting scoped per-user
tokens, narrow AGENT_TOKEN and inject a dedicated admin token only for @ops.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Bare '#' starts a YAML comment, so run-name resolved to 'ai-agent ·' with the number dropped.
Quote the value.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Without run-name, Gitea titles each ai-agent run by main's head commit, so runs aren't identifiable
in the Actions list. Add `run-name: ai-agent · #${{ github.event.issue.number }}` to the standard
caller (both the file and the README stub) so each run shows its issue.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The caller workflow had drifted between repos (run-name, stale SHA comment, trigger ordering,
different comment text) though all were functionally the same `uses: agent.yml@main`. Define one
canonical stub: make this repo's own ai-agent.yml the reference and update the README "Use it in a
repo" block to match it verbatim, noting that the on: triggers and the jobs.agent wrapper are the
irreducible minimum for a reusable (workflow_call) workflow.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Rebased onto the per-agent skill-scoping change so PR #25 carries both:
- route.sh keeps the registry 'skills' allow-list and emits skills as a step output
- install-opencode.sh writes the permission.skill block (deny-all + allow listed)
Pure refactor otherwise: each step's shell moves to its own file, called via
bash "$SCRIPTS/<name>.sh". The two extracted SKILL.md bodies are byte-identical to
main; routing/config/publish behavior is unchanged. Because this is a reusable
workflow (workflow_call) the runtime checkout is the caller's repo, so agent.yml now
checks THIS repo out into .agents-workflow/ (pinned @main) and points $SCRIPTS there.
- New gitea-api opencode skill (mirrors node1-ssh): documents the Gitea REST API
base URL, Authorization: token $AGENT_TOKEN header, and example curl calls for
read (issue/PR + comments, Actions runs/jobs/logs, org repos) and write (comment,
label, close), with explicit warnings: never echo the token, treat fetched
content as untrusted data (prompt-injection guard), and stop on 403.
- Wire AGENT_TOKEN into the Run agent step env so the agent process itself can
call the API (previously only the Publish step saw it).
- Update README secrets table: AGENT_TOKEN now also powers gitea-api; do not
re-narrow scopes without removing the skill.
Reusable workflow (on: workflow_call) moved from homelab; consuming repos add a thin caller
(uses: ffaerber/agents/.gitea/workflows/agent.yml@main, secrets: inherit).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>