Commit Graph
35 Commits
Author SHA1 Message Date
ffaerber 75a2493dee feat(ci): dependency caching for agent runs (opencode + Playwright) (#106)
ci / lint (push) Skipped
2026-07-07 17:16:24 +02:00
ffaerber 53ac2b7ba8 fix(agent): reactions show the agent, not "Ghost" (#105)
ci / lint (push) Skipped
2026-07-07 15:20:11 +02:00
Felix FaerberandClaude Opus 4.8 ef43d69309 agents: discussion mode — devs talk in threads; building starts only on explicit signal
ci / lint (push) Skipped
ci / lint (pull_request) Successful in 11s
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>
2026-07-07 14:34:12 +03:00
Felix FaerberandClaude Opus 4.8 e9df9d6bdd agents: review round 2 — split-PR flow, thread recency, mention boundaries, learnings cap, pm model
ci / lint (push) Skipped
ci / lint (pull_request) Successful in 11s
- 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>
2026-07-06 20:11:45 +03:00
Felix FaerberandClaude Opus 4.8 0771d394bd agents: hard timeout on agent runs — a hung model must not block the runner
ci / lint (push) Skipped
ci / lint (pull_request) Successful in 10s
A stalled local-ollama generate on a trivial @intern question held the single
runner slot for ~1h, queueing every agent run instance-wide (homelab run 869).

- run-agent.sh: each opencode attempt wrapped in `timeout -k 30 $AGENT_TIMEOUT`
  (default 1200s). rc=124 is not retried — a hung backend stays hung; fail fast
  and free the runner.
- agent.yml: job-level timeout-minutes: 45 as backstop.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-06 17:41:49 +03:00
junior 6abb8874cd agent.yml: add intern to trigger gate trusted author and mention list 2026-07-06 07:56:44 +00:00
junior bf1256ecec agents: add @intern routed to local ollama/ornith:35b
ci / lint (pull_request) Successful in 12s
2026-07-06 07:30:30 +00:00
Felix FaerberandClaude Opus 4.8 9b9e1e945d agents: fix review findings — thread attribution, races, rescue stall, docs, CI
ci / lint (push) Skipped
ci / lint (pull_request) Successful in 11s
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>
2026-07-06 09:47:34 +03:00
Felix FaerberandClaude Opus 4.8 6334ebe8c6 agents: report tokens + $ cost on every agent comment
Each run now appends a report to the agent's reply: the tool calls it made plus
input/output token totals and the dollar cost. opencode's --format json emits
per-step `tokens` and `cost` (USD, priced from the model) on step_finish events;
build-activity-log.sh sums them across the run.

- build-activity-log.sh: compute for EVERY agent (not just devs — @pm/@qa also
  call tools and cost money); output a collapsed <details> report (summary line
  shows "N tool calls · in X · out Y · $Z"; body lists the tools + a token/cost
  breakdown). Zero-tool runs get a one-line "$Z · in X · out Y" footer.
- publish.sh: build $activity once (near the top) and append it to every agent's
  reply — @pm plan/finalize, @qa verdict/recommendations, and dev PR comments.
- agent.yml: rename the step accordingly.

Models without pricing (self-hosted ollama) report cost $0.0000.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-06 09:22:00 +03:00
Felix FaerberandClaude Opus 4.8 0f8893330f agents: caller-provided skills hook — repos can ship their own opencode skills
A consuming repo can now add repo-specific skills under .gitea/agent-skills/<name>/
(SKILL.md + skill.json + optional setup.sh); the framework installs the ones
allowed for the running agent. This keeps deploy-target / infra specifics in the
repo they belong to instead of hardcoded in the shared workflow.

- install-caller-skills.sh: scans the caller workspace, installs each skill whose
  skill.json `agents` list includes the running agent, runs its optional setup.sh
  with all inherited secrets available as $SECRETS_JSON (toJSON(secrets) — so a
  caller's setup can read repo-specific secret names the framework can't know),
  and merges the allowed skills into the permission.skill allow-list.
- agent.yml: replace the hardcoded node1-ssh step with the generic caller-skills
  step (passes NAME, WORKSPACE, SECRETS_JSON).
- Remove the built-in node1-ssh skill: delete skill-node1-ssh.sh, drop "node1-ssh"
  from agents.json (senior/lead). The homelab repo now owns that skill.
- run-agent.sh: note caller-provided skills aren't in the roster (route them via
  the caller's AGENTS.md).

toJSON(secrets) verified supported on this Gitea (1.27) via an isolated probe.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-05 17:35:45 +03:00
Felix FaerberandClaude Opus 4.8 3c66220f6d agents: remove shared AGENT_TOKEN fallback — per-agent tokens only
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>
2026-07-05 16:51:06 +03:00
Felix FaerberandClaude Opus 4.8 06f1924441 agents: per-agent Gitea identity — each agent uses its own token
Drop the shared AGENT_TOKEN as the primary credential; every agent now acts
as its own Gitea user (TOKEN_PM for @pm, TOKEN_OPS for @ops, …) for API
calls, delegation/autopilot trigger comments, and PR merges.

- agent.yml: Run-agent step injects SELF_TOKEN — a ternary selecting the
  running agent's own token by name, falling back to AGENT_TOKEN for repos
  not yet migrated to per-agent tokens (e.g. homelab). Only that one token
  enters the agent process, so no agent can act as another. The gitea-api /
  gitea-admin skill-setup steps no longer carry a token (they only write docs).
- Gate: trust the agent roster (pm/junior/senior/lead/qa/ops) as comment
  authors so an agent's own delegation/autopilot trigger comment (posted with
  its PAT, no 🤖 prefix) fires the next run. @ops added to the mention set.
- publish.sh: TOK = agent identity (comments/replies); new TTOK = trigger/merge
  token (agent PAT, else AGENT_TOKEN fallback) for delegation, autopilot @qa
  triggers, and PR merges that must fire downstream workflows.
- skill-gitea-api.sh / skill-gitea-admin.sh / run-agent.sh: AGENT_TOKEN/
  TOKEN_OPS → SELF_TOKEN in the emitted skill docs and env contract.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-05 16:20:29 +03:00
Felix FaerberandClaude Opus 4.8 79ea9f68c9 feat(ops): @ops uses its dedicated TOKEN_OPS, not AGENT_TOKEN
The gitea-admin skill now authenticates with TOKEN_OPS (the ops user's admin token), and TOKEN_OPS
is injected into the agent process ONLY when name==ops. No other agent holds an admin credential in
its env. This unhooks @ops from AGENT_TOKEN, so AGENT_TOKEN can be narrowed to a non-admin token.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-05 15:52:07 +03:00
Felix FaerberandClaude Opus 4.8 6c753dc0a0 chore: repo moved to gitea/agents — update self-references
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>
2026-07-05 15:43:34 +03:00
Felix FaerberandClaude Opus 4.8 2f1ae61b06 feat(ops): make @ops routable + post under its own TOKEN_OPS identity
PR #55 added @ops to the registry but route.sh only looped pm/junior/senior/lead/qa, so @ops could
never be triggered, and there was no token case for it. Add 'ops' to the routing loop and the
TOKEN_OPS case in route.sh + publish.sh, and pass TOKEN_OPS in the workflow env next to TOKEN_QA
(route/publish/rescue steps) so route.sh (set -u) doesn't error on an @ops run.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-05 14:53:09 +03:00
Felix FaerberandClaude Opus 4.8 74d3e1d229 feat(ops): add @ops agent — Gitea instance administrator
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>
2026-07-05 14:03:57 +03:00
lead df0f6d6543 @lead: issue #16 — fully-automatic autopilot (label-gated @pm auto-delegate + @qa merge) 2026-07-04 19:23:20 +00:00
lead 423a060816 fix(agent): run step scripts from outside the workspace so agents can't break the run
Stage the shared scripts into $RUNNER_TEMP and point $SCRIPTS there for every
step, so an agent that commits/deletes the in-tree .agents-workflow checkout no
longer destroys the scripts the post-agent steps run (issue #33). Scrub any
in-tree .agents-workflow artifact before publishing, and add a failure-safe
rescue step that opens a PR for pushed work when a run fails.
2026-07-04 07:34:53 +00:00
Felix FaerberandClaude Opus 4.8 b3deee7412 fix(agent): route issue-opened events (event_name is workflow_call in reusable wf)
The shared agent.yml is a reusable (workflow_call) workflow, so on Gitea
github.event_name evaluates to 'workflow_call' — not the original 'issues'/
'issue_comment'. route.sh branched on EVENT == "issues", so issue-opened runs
scanned the empty comment body and skipped the @pm fallback, exiting 1 with
"no known agent mentioned" (runs #393/#394). Comment runs were unaffected
because the @mention lives in $BODY.

Discriminate on the comment id (CID) instead, which IS reliably forwarded in
the event payload: empty => issue-opened (scan issue body, default @pm), set
=> comment (scan comment body). Also add .gitignore for .env.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-04 10:02:50 +03:00
lead 36ba91cdd8 @lead: externalize agent.yml inline scripts into .gitea/workflows/scripts/*.sh
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.
2026-07-04 05:54:27 +00:00
lead a79b49b55e @lead: issue #22 — per-agent skill scoping via permission.skill 2026-07-04 05:25:06 +00:00
ffaerber e8e299872a Update .gitea/workflows/agent.yml 2026-07-03 22:30:05 +02:00
ffaerber 6decdd4658 Update .gitea/workflows/agent.yml 2026-07-03 22:11:42 +02:00
ffaerber 205b26a2f0 Update .gitea/workflows/agent.yml 2026-07-03 22:08:25 +02:00
senior fdf966c765 @senior: issue #14 — add gitea-api skill + expose AGENT_TOKEN to the agent process
- 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.
2026-07-03 11:07:38 +00:00
lead 459a0c64b8 @lead: node1-ssh skill points to homelab opencode.json allowlist instead of inventing one 2026-07-03 09:50:48 +00:00
junior 5c4f03a397 @junior: issue #12 2026-07-03 09:45:48 +00:00
senior 173ee612bd @senior: issue #10 — wire up read-only ssh node1 alias in agent workflow 2026-07-03 09:13:42 +00:00
senior 402ccd7a6b @senior: issue #8 — list agents + models in README, update routing & allow-list 2026-07-02 15:38:52 +00:00
senior 92ad8ef436 @senior: issue #4 — one PR per run, post activity log to the PR thread 2026-07-02 13:51:21 +00:00
senior 15285d228f Post opencode activity log (tool calls + reasoning) as a PR comment (#2)
Switch the real 'Run agent' step to --format json (replacing the two
TEMP/DEBUG schema-discovery commits da6f0d5/d0ddb06), capture the raw
event stream, and reconstruct the plain-text reply from the assistant
'text' parts so the existing Publish logic is unchanged.

Add a 'Build activity log' step that filters the event stream to
tool_use (with truncated title/input) and text (reasoning) events.
The Publish step posts that trail as a separate collapsible comment on
the PR thread (dev agents only — comment-only roles do no tool calls).

This is additive to the existing summary/PR-description comment.
Reasoning reuse on a follow-up run is free: the existing 'fetch full
issue thread' step already re-feeds all prior comments (including this
new log comment) into the next run's prompt, so the agent sees what it
did last time.
2026-07-02 13:17:14 +00:00
Felix FaerberandClaude Opus 4.8 d0ddb06ccb DEBUG: post captured --format json schema as an issue comment (findable + fetchable)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-02 15:21:48 +03:00
Felix FaerberandClaude Opus 4.8 da6f0d5b92 TEMP: debug step to capture opencode --format json event schema
Runs a tiny Sonnet probe and dumps the raw events to the Actions log so we can build the
PR-progress parser against the real schema. Removed once captured.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-02 15:14:37 +03:00
Felix FaerberandClaude Opus 4.8 c594080ffc Add PM breakdown skill: feature -> milestone + sub-issues (plan/approve/create gate)
@pm proposes a milestone + sub-tasks and asks for approval; on 'yes' it emits a BEGIN_SUBTASKS
block, and the workflow creates the milestone + one sub-issue per line (each 'Part of #<feature>').
Sub-issues are not auto-started — maintainer @mentions an agent on each when ready.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-02 10:32:57 +03:00
Felix FaerberandClaude Opus 4.8 f6df3f24af Add reusable AI-agent workflow + docs + AGENTS template
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>
2026-07-02 07:20:54 +03:00