Table of Contents generated with DocToc
| Field | Value |
|---|---|
| RFC | AI-0004 |
| Title | Principles of agentic interaction for open-source maintainers |
| Status | Draft |
| Authors | The Apache Magpie project (see MISSION.md for roster) |
| Initial draft | 2026-05-07 |
| Supersedes | None |
| Superseded by | None |
| Reference implementation | apache/magpie |
| License | Apache License 2.0 |
This RFC describes six principles that govern how AI agents should interact with open-source projects when the human in the interaction is a project maintainer — committer, PMC member, release manager, security-team member, triager. The six principles — (1) human-in-the-loop on every state change, (2) secure sandbox by default, (3) vendor neutrality across LLM backends and project governance, (4) conversational, correctable agentic skills, (5) write access and outbound messages require human review, and (6) privacy by design — are framed as a baseline. They define the minimum trust posture under which agentic tooling can be ethically deployed against the public artefacts of a community-governed project (issues, PRs, mailing lists, releases, security reports, contributor data).
The RFC is normative for the Apache Magpie framework (apache/magpie, the working draft of which is summarised in MISSION.md) and is offered as a pattern other projects can adopt or adapt when integrating agentic tooling into their own maintainership workflow.
It is not a specification of any particular implementation detail (LLM choice, prompt format, model size, scaffolding library). The principles are independent of those choices.
This is a Draft. The Apache Magpie project‘s reference implementation operationalises every principle in this RFC, but the RFC itself is the project’s first attempt to extract the principles from the implementation and frame them as a portable contract. The next two milestones are:
Draft to Stable.Maintainers of open-source projects increasingly find themselves at the receiving end of agent-shaped tooling — bots that triage, auto-mergers that touch their default branch, scanners that file issues, AI-suggested PRs that propose code. The volume of such tooling is growing faster than the conventions for how that tooling should behave. The result, today, is a stack of implicit choices made by individual tool authors that vary across projects in ways that erode trust:
~; some read nothing. Some can gh pr create; some can silently push to the default branch. The maintainer is on the hook for figuring this out.This RFC names the four shifts that, taken together, make agentic tooling acceptable on a maintainer-governed project. Each shift is independently necessary; the combination is sufficient.
| Term | Definition |
|---|---|
| Agent | A program that selects and executes actions to advance a maintainer-stated goal, where at least one of those actions is mediated by an LLM and where action selection is conditioned on natural-language conversation rather than a pre-coded flow chart. |
| Skill | A package of agent-readable text (typically a markdown file with YAML frontmatter and bundled scripts/references) that scopes the agent to a single workflow. The Apache Magpie framework's skills (security-issue-import, pr-management-triage, etc.) are reference instances. |
| Maintainer | A human with write access (or comparable governance authority) on the target project. PMC members, committers, triagers, release managers all qualify; bots and agents do not. |
| State change | Any operation observable by parties outside the maintainer‘s local machine: posted comment, edited issue body, applied label, merged PR, sent email, written file under the repo’s tracked path, etc. Operations that touch only the maintainer's /tmp or ~/.config/<framework>/ cache are not state changes. |
| Confirmation | An explicit, in-session, reversible-only-by-history act by the maintainer that authorises one specific state change. Standing approvals, “yes to all”, and pre-approved-via-config are explicitly not confirmations. |
| Sandbox | An OS-level isolation boundary (filesystem namespacing, network filtering, syscall mediation) plus a tool-permissions layer plus a clean-environment wrapper, applied to every agent-launched subprocess. |
Every state change an agent proposes against project artefacts MUST be presented to a maintainer as a proposal, and MUST NOT be applied until the maintainer issues an explicit per-proposal confirmation. The agent never confirms on the maintainer's behalf, never persists “always yes” approvals across sessions, and never bundles multiple state changes under one confirmation in a way that hides any single one from review.
A skill that triages 200 PRs in 10 minutes is doing 200 state changes. If the maintainer is not in the loop on each one, what they are doing is delegating their committer authority to a program. That is not what “AI-assisted maintainership” should mean. The committer‘s signature on every artefact is the entire basis of the project’s trust model; the agent does not own that signature.
all as a one-keystroke shortcut is acceptable; the agent must still surface every item before honouring it.Agentic Autonomous (“limited fix-and-merge”, in Apache Magpie's terminology) is the explicit exception. It permits auto-merge, but only after all of the following gate conditions hold:
docs/contributor-sentiment.md for the evaluation methodology and the four signal dimensions (thread tone, time-to-first-reply, first-PR retention, reviewer load) that constitute this gate.The carve-out exists because lint-rebase-format has marginal human value and should not require a human in the loop forever. It is off by default in the reference implementation. A project that turns it on without first running the manual loop has skipped the proof.
The agent‘s executing process MUST run inside an OS-level sandbox at all times. The sandbox MUST default-deny filesystem reads outside the project working tree and a small set of explicitly-permitted user-config paths, default-deny network egress to all hosts not on a project-declared allow-list, and default-deny invocation of binaries that the project’s permission policy has not explicitly allowed. The sandbox is in addition to — not in replacement of — Principle 1's human-in-the-loop confirmation gate.
LLM-driven agents read attacker-controlled text every time they run. Email subjects, PR titles, scanner findings, public commit messages, mailing-list archives, third-party PR comments — all of these are content the agent treats as input and that an attacker can shape. No prompt-engineering technique neutralises this surface. The fallback when prompt engineering fails has to be the operating system telling the agent's subprocess “no, you cannot read ~/.aws/credentials” or “no, you cannot connect to attacker.example.com”.
The reference implementation (see docs/setup/secure-agent-internals.md) uses a three-layer model. Other implementations MAY choose different mechanisms; the layering MUST be preserved:
| Layer | What it stops | Mechanism (reference) |
|---|---|---|
| 0. Clean environment | Inherited credential-shaped env vars ($AWS_*, $GH_TOKEN, $ANTHROPIC_API_KEY, …). | A shell wrapper (claude-iso) that strips the agent's process env to a project-declared whitelist before exec. |
| 1. Filesystem + network sandbox | Bash subprocess reads outside the project tree; outbound HTTPS to non-allowed hosts. | Linux: bubblewrap user-namespace + socat SNI proxy. macOS: sandbox-exec. |
| 2. Tool permissions | The agent's own Read/Edit/Write/Bash tools touching denied paths or binaries. | The agent host‘s permission system (e.g., Claude Code’s permissions.deny). |
| 3. Forced confirmation | Visible-to-others writes that haven't been seen by a human. | permissions.ask for every state-mutating shell call (e.g., gh pr create, gh issue edit, gh gist *, gh secret *). Implements Principle 1 at the OS layer. |
settings.json (or equivalent). "I’ll just allow ~/" is not an answer.Bash(curl *), Bash(wget *)) is a friction layer that catches sloppy injection. The network allow-list is the actual control. Document this honestly; do not pretend the permission layer is the boundary.export GITHUB_TOKEN=… in their shell once should not have that token visible to every agent subprocess thereafter. The wrapper is the only reason the agent's child gh call does not see your personal access token by accident.printf '%s' for attacker-controlled text — any string that originated outside the framework (email subject, PR title, scanner finding, reporter-supplied free text) MUST NOT be inlined into a single- or double-quoted shell argument. Write it to a tempfile via printf '%s' "$value" > /tmp/x (no expansion) and pass via gh api ... -F field=@/tmp/x (verbatim from disk).Bash(*) and pray. A blanket allow-bash with a long deny-list misses every wrapper-interpreter trick (python3 -c, node -e, bash -c '…', c''url …, /usr/bin/curl …, chained pipelines on macOS). The deny-list is advisory; the control is the network allow-list.--body "$x" interpolation. Shell expansion of attacker-controlled text inside double quotes is the most common shell-breakout vector and the prek hooks do not catch it. Use --body-file <path> instead, always.github.com silently authorises gh gist create / gh repo create --public. Confirmation prompts (permissions.ask) on every state-mutating gh call are how Principle 1 meets Principle 2 at the OS layer.The framework MUST NOT bind a maintainer‘s workflow to any single LLM vendor, model size class, hosting provider, or project-governance model. A skill that “works with Claude” MUST be expressible in a form that other LLM agents can consume; a workflow that integrates an ASF release process MUST work, with config substitution only, against a non-ASF project’s release process.
Axis A — LLM backend neutrality. Skills are markdown-with-YAML, not vendor-specific prompts. The agentic host (Claude Code, Codex, Gemini CLI, a local-Ollama wrapper, a future Apache-aligned agent runtime) consumes the same skill file and behaves comparably. The reference implementation documents this explicitly: skills are “language-independent, since SKILLs are English; standard Python ecosystem dependencies for the deterministic-output scripts; no AI SDK integration needed”.
Axis B — Project-governance neutrality. ASF integrations (private mailing lists, Vulnogram CVE flows, PMC roles, ASF release process) are configurable, not hardcoded. A non-ASF adopter swaps in a private GitHub repo, GitHub Security Advisories, a maintainer roster, their own release process — and the same skill executes. The reference implementation's placeholder convention (<tracker>, <upstream>, <security-list>, <private-list>) and the <project-config>/ adapter dir are how this is operationalised.
tools/<adapter>/ directories (tools/cve-tool-vulnogram/, tools/gmail/, tools/ponymail/) are this pattern.tools/privacy-llm/ for the reference gate.claude-pr-review is a skill that ages out the day a maintainer wants to use another agent. Tools are named for what they do, not what runs them.apache/<project> strings hardcoded into a skill make the skill ASF-only by accident. Placeholder discipline (<upstream>, <tracker>, <security-list>) is the cheapest way to keep the option open.The agent‘s behaviour MUST be expressed as agent-readable markdown (skill files) that the maintainer can read, understand, override locally, and contribute back upstream through the normal patch workflow. The conversation between maintainer and agent — including the corrections the maintainer makes when the agent gets it wrong — MUST be the primary mechanism by which the framework’s skills evolve.
The instinct from twenty years of writing services is to encode behaviour in code, configuration files, or YAML. An agent's prompts and skill files are code in every meaningful sense, but their “compile” step is the conversation that follows. The maintainer notices the agent is using the wrong tone in mentor replies, edits the skill's tone block, the next invocation behaves differently, and (after a stabilisation period) the edit is upstreamed.
The shift the maintainer makes is from “this tool needs a code change” to “this skill needs a markdown edit”. The shift the framework makes is from “user-of-tool” to “co-author-of-tool”.
.apache-magpie-overrides/<skill>.md convention lets a maintainer encode “for this project, do X differently” without forking the framework. The override file is committed in the adopter’s repo; the framework reads it at runtime and merges agent-readable modifications before executing the default behaviour.setup-override-upstream skill (or equivalent) walks the maintainer through promoting the override into a framework PR. Some overrides stay local forever (project-specific policy); some belong upstream (general improvement). The framework MUST surface the choice explicitly.--repo argument; my project uses --repository” and the agent acknowledges, applies the change in this session, and surfaces the override-file path so the correction persists across sessions. The maintainer is not expected to know the framework's source layout to make a behaviour change stick.Every operation that mutates state visible to parties outside the maintainer‘s local machine — every
git push, everygh issue create / edit / close / merge, every label add / remove, every label-driven workflow trigger, every outbound email, every Slack / IRC / Matrix / mailing-list post, every release artefact upload — MUST be reviewed by the maintainer in its final, post-render form before it is sent. The agent’s role on the outbound path ends at “draft prepared”. The press of Enter / Send / Submit is the maintainer's, on a surface where the maintainer can inspect the literal bytes that will land.
This principle is the operational specialisation of Principle 1 for the two highest-blast-radius surfaces: write access to the project's source-of-truth (the git repo, the issue tracker, the project board, the release surface) and outbound communication on the project's behalf (email to mailing lists, replies to security reporters, comments tagged with the maintainer's handle).
The general HITL principle catches “the agent is mutating state”. The two surfaces below need their own callout because they share three properties that make them especially unforgiving:
main propagates to every downstream user; an email to users@<project> reaches every subscriber. The cost of a wrong byte is multiplied by the audience size.gh pr create --web over gh pr create. When opening a public pull request, the framework's flow ends at “opening the browser at the PR-create page with the body pre-populated”. The maintainer reviews in the browser and clicks the Create pull request button themselves. Same for gh issue create --web and equivalent flows.--body-file over --body for any gh issue comment / gh pr comment / gh issue create / gh pr review invocation that is automated. The body must be a file the maintainer reads before the call runs. String-form --body "$x" re-introduces shell expansion at the wrong layer and is forbidden — see Principle 2 — anti-patterns.gh token, git push credentials, mailing-list submission key, etc. are visible to the agent’s subprocess only because the project‘s clean-env wrapper deliberately passes them through (see Principle 2 layer 0). They are not inherited from the maintainer’s interactive shell. The framework's permission policy MUST forbid the agent from reading the on-disk credential file directly (Read(~/.config/gh/**), Read(~/.netrc), etc.); the credential surface is only what the parent process already negotiated and forwarded.draft and send modes the agent can pick from. The framework‘s drafting tool MUST NOT expose a send action at all; only the human’s mail client can send.@maintainer-handle is indistinguishable to readers from the maintainer. If the comment has to be attributed to a human, a human writes it (or signs off on a draft and posts it under their own handle).permissions.ask layer for state-mutating gh calls — that is how this principle is enforced at the OS layer.Private content — security-issue reports, embargoed CVE detail, PMC-private mail, contributor PII (full names, email addresses, IPs), reporter-supplied test artefacts — MUST be handled by the framework as if it had a chain-of-custody requirement. Specifically: (a) only LLMs the project's PMC has explicitly approved may receive private content; (b) PII MUST be redacted before any LLM read where the content is not strictly needed for the task; (c) the framework MUST provide a per-skill gate that verifies the LLM-of-the-moment is approved before any private read happens; (d) every outbound public artefact (CVE record, public advisory, public-PR description) MUST be mechanically checked for private content leakage before it leaves the framework's control.
Privacy and security overlap but are not identical. Security (Principle 2) defends against the agent doing the wrong thing. Privacy defends against the agent doing the right thing with the wrong audience. A correctly-functioning agent that forwards a security report's reporter-PII to a non-approved external LLM has not been compromised — it has been used as designed against a privacy boundary the framework should have enforced.
The reference implementation operationalises this principle in tools/privacy-llm/ — see docs/setup/privacy-llm.md for the adopter-facing setup and tools/privacy-llm/wiring.md for the redact-after-fetch protocol that every skill reading Gmail private mail follows.
tools/privacy-llm/checker/) enforces the gate but the policy is the project's. The reference list defaults to “Claude Code trusted; *.apache.org auto-approved; localhost for local-inference setups; everything else requires explicit opt-in.”tools/privacy-llm/redactor/) before the LLM sees them. Reporter names → N-<hash>, email addresses → E-<hash>, IPs → IP-<hash>. The skill operates on the hash-prefixed identifiers; the reverse map lives only on the maintainer’s local disk (mode 0600, never committed), and the reveal step happens at draft-write time inside the maintainer's own process, not inside an LLM call.credits[] field) is a deliberate output and passes through unredacted, only after the maintainer confirms the credit shape with the reporter on the inbound thread.CVE-\d{4}-\d{4,7} (forbidden in pre-disclosure public PRs), reporter names from the private mapping table, mailing-list addresses, and any string the project's policy file enumerates as private. The scrub fires before the draft is shown to the maintainer; failures stop the flow with a specific message.N-<hash>) and the local mapping resolves them only when a maintainer opens a specific audit entry on their own machine.The privacy gate‘s policy is set by the project’s PMC; the gate‘s implementation is vendor-neutral by construction (Principle 3). A frontier-model backend, a local Ollama instance, and an Apache-aligned endpoint all pass through the same gate-check. The gate accepts or rejects based on the endpoint’s hostname / identity, not on which company hosts it.
tools/privacy-llm/pii.md enumerates them).tools/privacy-llm/ (the gatedocs/setup/privacy-llm.md.tools/privacy-llm/pii.md.tools/privacy-llm/wiring.md.The six principles are independently necessary; together they form a cycle the maintainer can repeatedly apply:
┌──────────────────────────────────────────────────────┐ │ │ ▼ │ [Skill] ─── proposes ──▶ [Maintainer] ─── confirms ──▶ │ ▲ │ │ │ │ corrects │ │ ▼ │ │ [Override file] ─── upstream ──┘ │ │ └────── reads at runtime ──────┘ Sandbox is under everything. (2) Vendor neutrality means any LLM can play the [Skill] role. (3) Write / send is a maintainer click, never the agent's. (5) Private content stops at the approved-LLM gate. (6)
Drop any one of the six and the system regresses to a recognisable bad pattern: drop (1) and you have an autonomous agent the maintainer is on the hook for; drop (2) and one prompt injection ruins the day; drop (3) and the project becomes a vendor‘s cost centre; drop (4) and the skill is a black box only the framework’s authors can fix; drop (5) and the agent is sending mail in the maintainer‘s voice; drop (6) and a security reporter’s PII ends up in a vendor's training corpus.
A project that wants to adopt these principles without adopting Apache Magpie as a whole has the following minimum bar:
bubblewrap + a network-allow-list HTTP proxy is one day‘s work. On macOS, a sandbox-exec profile is similar. The agent’s parent shell runs in the sandbox; every subprocess inherits.skills/ directory under your project‘s main repo or a sibling <project>-magpie repo. PR them. Review them. Diff them. Don’t hand-edit them on production machines without committing.<project-config>/ directory with documented placeholders and let the skills consult them.The Apache Magpie project is happy to consult on the lift — see MISSION.md for the maintainer- education stream.
MISSION.md.This RFC distils principles operationalised in the Apache Magpie reference implementation. The PMC roster and collaborator list (see MISSION.md) includes the people whose discussion, code, and incident-review work shaped these principles. The framing of the principles here owes a particular debt to the 2026-05 prompt-injection audit (gist) that surfaced the Principle 2 specifics, and to the Agentic Triage/Agentic Mentoring/Agentic Drafting/Agentic Autonomous swimlane discussion that surfaced the carve-out structure of Principle 1.