Initial import: 10 Radix skills across 3 categories
Kategoriserer danske regnskabs-/ERP-skills, ERP-data-afstemnings-
skill og to devops-workflows (gitea-issue-agent, kanban-workflows)
som Radix-medlemmers AI-agenter kan dele.
Struktur:
skills/<kategori>/<skill-navn>/SKILL.md
skills/<kategori>/<skill-navn>/{references,templates,scripts}/
Indekseret af index.json (genereret af scripts/rebuild_index.py).
Kør `python3 scripts/rebuild_index.py --check` i CI for at fange
synkroniseringsfejl.
This commit is contained in:
@@ -0,0 +1,101 @@
|
||||
# Identity and safety in the Gitea issue agent
|
||||
|
||||
## Two identities, one Gitea server
|
||||
|
||||
The setup has two Gitea users that should remain separate:
|
||||
|
||||
| Identity | Token stored in | Used for | What it posts |
|
||||
| --- | --- | --- | --- |
|
||||
| **Service-bruger** (e.g. `hermes-issues`) | `GITEA_TOKEN` in `~/.hermes/.env` | All plugin tool calls: scan, comment, create PR | Comments and PRs attributed to the bot |
|
||||
| **Personal user** (e.g. `dennis`) | `tea` login + `~/.netrc` | Local `git push` of branches the agent created | Commits and merges attributed to you |
|
||||
|
||||
The plugin's `gitea_agent_status` reports `authenticated_user`. If it
|
||||
reports your personal login, the bot will post comments as you — fix
|
||||
the `GITEA_TOKEN` before scheduling any cron job.
|
||||
|
||||
## Why the Hermes safety-guards exist (and why the agent can't bypass them)
|
||||
|
||||
Hermes has three layers of "agent cannot edit" protection, all by
|
||||
design:
|
||||
|
||||
1. **`~/.hermes/config.yaml`** — gates plugin load, model selection,
|
||||
toolsets, gateway config. An agent that could rewrite this could
|
||||
give itself new tools, change providers, or open outbound network
|
||||
channels. The `patch` tool explicitly refuses:
|
||||
`Refusing to write to Hermes config file: ... Agent cannot modify
|
||||
security-sensitive configuration.`
|
||||
|
||||
2. **`~/.hermes/.env`** — contains API keys, tokens, passwords. The
|
||||
`write_file`, `patch`, and `execute_code` tools all refuse to
|
||||
modify it.
|
||||
|
||||
3. **`execute_code` with file writes** — when a script is going to
|
||||
write files under `~/.hermes/`, the safety guard blocks it
|
||||
unconditionally: `BLOCKED: execute_code script timed out without
|
||||
user response.`
|
||||
|
||||
**The right move when blocked:** give the user the exact one-line
|
||||
edit (or `cat > file <<EOF ... EOF` block) and stop. Do not try
|
||||
alternative tools, do not retry, do not work around it. The user
|
||||
must run the edit themselves.
|
||||
|
||||
This is not a bug. It is the threat model.
|
||||
|
||||
## Approval-gate design rationale
|
||||
|
||||
The agent should never implement, push, or open a PR for an issue
|
||||
that hasn't been approved. This protects against three classes of
|
||||
mistake:
|
||||
|
||||
1. **Misread issue** — the user wanted "fix the X button", the agent
|
||||
rewrote `X()` in 14 files. Approval forces a human to look at the
|
||||
proposal first.
|
||||
2. **Out-of-scope issue** — the user wanted to push back, not fix.
|
||||
Approval makes "no" cheap (just don't reply).
|
||||
3. **Bad agent day** — the LLM hallucinated, the issue got a wrong
|
||||
proposal, the agent is in a weird state. Approval makes the loop
|
||||
recoverable without reverting commits.
|
||||
|
||||
The two state markers (`proposal`, `pr_ready`) survive Hermes
|
||||
restarts, plugin reloads, and Gitea restarts, because they live in
|
||||
the issue's comment history. The agent never has to remember
|
||||
anything to resume — it can re-scan and pick up where it left off.
|
||||
|
||||
## Approval matching — why it requires a known login by default
|
||||
|
||||
The default approval regex is permissive enough to handle Danish
|
||||
("godkend", "godkender") and English ("approve", "approved", "ok",
|
||||
"go") in either order with the agent mention. But without a
|
||||
known-login check, **any user** with write access to the repo could
|
||||
say "looks good, agent" in a comment and trigger a push. That's a
|
||||
prompt-injection vector — a malicious screenshot, or a co-worker
|
||||
joking, could authorize code execution.
|
||||
|
||||
Two safe modes:
|
||||
|
||||
- **Label-only mode** (the default until `GITEA_APPROVER_LOGIN` is
|
||||
set): a maintainer applies one of three labels. Labels can only
|
||||
be applied by users with write access, so the trust surface is
|
||||
the maintainer set, not "anyone who can comment".
|
||||
- **Login-gated mode** (once `GITEA_APPROVER_LOGIN` is set): a
|
||||
comment from that specific user, matching the regex, AND
|
||||
after the latest proposal comment. This is the strict mode.
|
||||
|
||||
If the user wants both, both work — labels OR login-comment. If they
|
||||
want neither (auto-implement everything), they should set both
|
||||
`GITEA_APPROVER_LOGIN` and approve a *meta-issue* saying "always
|
||||
implement" — but that's not the default and not recommended.
|
||||
|
||||
## The first run is always manual
|
||||
|
||||
Before scheduling a cron, the user must:
|
||||
|
||||
1. Run a manual `gitea_issue_agent_scan` and confirm issues show up.
|
||||
2. Pick a real issue and walk it through: scan → fetch images →
|
||||
analyze → propose → wait → approve → implement → test → push →
|
||||
PR.
|
||||
3. Confirm the PR body links to the issue, the commit message is
|
||||
reasonable, and `git log` shows the expected author/email.
|
||||
4. **Then** schedule a cron. The cron prompt itself should be
|
||||
minimal — "scan, propose for new issues, implement approved" —
|
||||
with a clear hand-off to the skill for the details.
|
||||
Reference in New Issue
Block a user