aider-delegate
Delegate a coding task to Aider (`aider`) as a background implementer, then review its diff and land it yourself. Use this whenever the user wants to hand implementation work to Aider - phrasings like "have Aider do X", "delegate this to aider", "run it through Aider", or "use Ai
Install
npx skills add https://github.com/amElnagdy/delegate-skills/tree/master/skills/aider-delegate
claude plugin marketplace add https://llmmart.ai/marketplace.json && claude plugin install amelnagdy-delegate-skills@llmmart
git clone https://github.com/amElnagdy/delegate-skills.git
The skills CLI installs just this skill, for any of its supported agents. Claude Code installs the whole amelnagdy/delegate-skills collection as a plugin from our marketplace. Git is the plain clone.
Skill manifest
Aider Delegate
You are the orchestrator. Hand a bounded coding task to a separate implementer - Aider - then review what it produced and land it yourself. You write the brief and own the judgment; Aider does the typing in its own run; you verify and commit.
The loop needs only a shell command and file access, so any comparable orchestrator can drive it.
The one thing to know about Aider
Aider commits by default. Two of its defaults would destroy the reviewable diff this skill exists to produce:
--auto-commits(defaultTrue) - Aider commits its own edits after each exchange.--dirty-commits(defaultTrue) - Aider commits your pre-existing uncommitted work before it starts editing.
The relay always passes --no-auto-commits and --no-dirty-commits, and neither is configurable
through it. If you ever drive aider by hand instead of through the relay, pass both yourself, or the
work lands as commits you never reviewed. The relay also passes --no-gitignore, because Aider
otherwise writes .aider* into .gitignore on startup and dirties the tree you are about to read.
When NOT to use this
- The task is small enough to do inline; delegation overhead is not worth it.
- The
aiderCLI is not installed, or no model is configured for it. - You want the implementer to manage its own commits. Aider can, but this skill deliberately turns that off - the diff is the deliverable.
Prerequisites (check once)
- Install Aider -
python -m pip install aider-chat, or the standalone installer from the Aider install docs. - Configure a model. Aider reads provider keys from the environment (
OPENAI_API_KEY,ANTHROPIC_API_KEY, …) or its own config; see Aider's model docs. - Confirm
aider --versionsucceeds. - Work in, or point
--cdat, the target git repository.
Choose the model
Aider uses its own configured model when --model is omitted. Pass --model <name> to pick another.
Local and self-hosted models
Aider talks to any OpenAI-compatible endpoint, so this is also the skill for delegating to a model
running on the user's own hardware - llama.cpp's server, Ollama, vLLM, LM Studio, or anything else
that serves the same API. Pair --model with --api-base:
node "<skill-dir>/scripts/relay.mjs" --brief brief.txt --cd /path/to/repo \
--model openai/<served-model-name> --api-base http://127.0.0.1:<port>/v1
Three things differ from a hosted provider:
- The
openai/prefix is required. It tells Aider to speak the OpenAI protocol to your endpoint; the part after it is whatever name your server reports, not a provider catalog name. - A placeholder key is still needed. Export any non-empty
OPENAI_API_KEY. The client library requires the header even when the server ignores its value. - Ask for a smaller edit format. Local models often fail Aider's default
diffformat, which requires exact search/replace blocks.--edit-format wholetrades tokens for reliability; keep the brief's scope tight with--fileso whole-file rewrites stay cheap.
A local endpoint that is not running looks like a hang, not an error: Aider retries the connection
until the relay's --timeout watchdog fires and reports status: "timeout". Confirm the server is up
before dispatching a long brief.
Staying offline
No account or provider registration is involved: Aider is a pip install, the endpoint is yours, and
OPENAI_API_KEY only has to be non-empty. The relay pins the flags that would otherwise reach the
network on their own - --no-check-update, --no-analytics (Aider's own default is random, which
opts some sessions in by itself), and --no-detect-urls, without which Aider offers to scrape any URL
in the brief and --yes-always accepts that offer silently.
--no-suggest-shell-commands closes the remaining path by which a run could reach the network without
being asked to. What stays outside the relay's control is the brief itself: instructions that tell
Aider to install a package or call an API will still be carried out, and --auto-lint runs the
repository's own tooling. Offline here means nothing in the dispatch path reaches out on its own - not
that a sandbox is stopping it.
The loop
Run these five steps per task. Steps 1, 4, and 5 require judgment; 2 and 3 are mechanical.
1. Write the brief
Aider sees only the text you send plus the files in its editing scope - no chat history or shared context. Include the goal, current state, what to change, what to leave untouched, the project's actual gates, and a report contract. Keep one task per brief. See references/writing-the-brief.md.
2. Dispatch
Use the bundled helper. It wraps Aider's headless --message-file mode, captures the run, and writes
result.json. (<skill-dir> is the installed folder containing this SKILL.md.)
node "<skill-dir>/scripts/relay.mjs" --brief brief.txt --cd /path/to/repo
# choose a model: add --model <name>
# point at an OpenAI-compatible server: add --api-base <url>
# scope the edit surface: add --file <path> (repeatable), --read <path> for context only
# dry run, no files modified: add --read-only
# continue the previous chat: add --resume-last (delta brief only)
# hard time limit (watchdog): add --timeout 2h (the 30m default suits short runs; implementation briefs routinely need 1-2h)
# see all options: node .../relay.mjs --help
The child process's cwd pins the workspace. The brief is delivered with --message-file, so it never
rides argv: it stays out of the host process list and clear of the OS argument size cap. The relay
writes artifacts under the system temp dir by default and never commits. See
references/dispatch-and-poll.md.
3. Wait for completion
The helper blocks until Aider finishes. Run it with the orchestrator's background-command facility, or
background it in the shell and poll for result.json. A pre-run usage error exits 2 and writes no
result; a missing aider exits 127 and writes status: "aider_unavailable".
Trust process state and the working tree over a progress display. Completion means the process exited
and result.json exists. Aider's report is the finalMessage field in result.json (also printed in
full on stdout between the report markers).
Aider exits 0 even when it never reached a model, so the relay scans the run for Aider's own endpoint
and authentication errors and reports status: "failed" when it finds one. Treat a failed status
with an error mentioning the endpoint as a configuration problem, not a coding failure.
4. Review - do not trust the self-report
Treat Aider's final message and gate claims as claims:
- Re-run the project's gates yourself.
- Read the diff against the brief, starting with
touchedFiles. - Run relevant guard skills if installed.
- Round-trip migrations and grep for dangling references after removals or renames.
Aider's --auto-lint is on by default, so it may have already run a linter and fixed its own
complaints. That is Aider's lint, not your gates - run yours anyway. See
references/review-and-land.md.
5. Land it
The implementer edits the working tree; the orchestrator commits. Commit only after the gates pass
and the diff holds. If rework is needed, send a delta brief with --resume-last, then review again.
Autonomy and permissions
The relay passes --yes-always, Aider's own term for auto-confirming every prompt, because a headless
run cannot answer one. Understand what that consents to in advance. Auto-confirmation applies to
every prompt Aider would otherwise raise, and Aider's prompts are not limited to file edits: left at
its defaults it also offers to run shell commands it has suggested, and --yes-always would accept
those with nobody reading them. The relay therefore pins --no-suggest-shell-commands, which removes
that path.
What remains is not a sandbox, and nothing here pretends otherwise. Aider has no permission modes and
no isolation: within its file scope it edits freely, and --auto-lint (on by default) runs whatever
linter the repository configures. A brief that tells Aider to run a command still gets a command run.
Delegation is the authorization; if a run must not be able to touch the host, run it in a container or
a throwaway worktree, because no flag in this relay will give you that.
File selection is not a security boundary. --file, --read, and --subtree-only set what Aider
puts in its chat context, which is a scoping and token-cost decision. They do not confine what it can
reach. See references/writing-the-brief.md.
--read-only maps to Aider's --dry-run, which performs the run without modifying files. The relay
does not independently verify that claim - it reports what git status --porcelain shows and warns if
a --read-only run left the tree changed. touchedFiles and the diff, not a flag, are the guarantee.
Resume
Aider has no session ids. Its resume unit is the chat history file it keeps in the repository
(.aider.chat.history.md), so --resume-last maps to Aider's --restore-chat-history and
--history-file pins a specific one. Because that history lives in the repo, resume is per-worktree,
not per-user: two clones of the same project do not share it.
Authorization model
Delegation is something the human opts into. Once they have ("run this queue", "proceed"), committing verified, gate-passing work is the agreed contract. Two limits remain: surface, don't absorb (report Aider's design decisions, defensible-but-unasked turns, and non-blocking nitpicks) and stop for scope changes (if correct completion needs going beyond the brief, ask instead of expanding the mandate). See references/review-and-land.md.
References
- references/writing-the-brief.md - structure, report contract, real gates, file scope, and delta briefs.
- references/dispatch-and-poll.md - flags, artifacts,
result.json, polling, and failure recovery. - references/review-and-land.md - review checklist, the commit boundary, and rework through Aider's chat history.
- references/multi-task-queues.md - sequential queues, constraint carry-forward, progress tracking, and the final coherence pass.
Files (delegate-skills)
-
references
-
dispatch-and-poll.md 9 KB
# Dispatch and poll The relay (`scripts/relay.mjs`) is the whole dispatch mechanic: it launches Aider headlessly, captures the run, and writes a structured `result.json`. Node built-ins only, no dependencies, and it never commits. ## Before the first run 1. `aider --version` succeeds. 2. A model is configured - either Aider's own default, or the `--model` you intend to pass. Provider keys come from the environment or Aider's config. 3. The target directory is a git repository. Without git the relay cannot report `touchedFiles`, and the diff is the deliverable. 4. The working tree is clean, or you know exactly what was already dirty. `touchedFiles` reports everything git sees, not only what Aider wrote. ## Dispatching ```bash node "<skill-dir>/scripts/relay.mjs" --brief brief.txt --cd /path/to/repo ``` | Flag | Effect | | --- | --- | | `--brief <file>` | Path to the brief. Omit to read it from stdin. | | `--cd <dir>` | Working root for Aider. Default: current directory. | | `--lane <name>` | Apply a fleet lane's dials from delegate-setup. Explicit flags win. | | `--model <name>` | Aider's `--model`. Default: Aider's own configured model. | | `--api-base <url>` | Aider's `--openai-api-base`, for an OpenAI-compatible server. | | `--edit-format <fmt>` | Aider's `--edit-format` (e.g. `diff`, `whole`, `udiff`). | | `--architect` | Aider's `--architect` edit format. Mutually exclusive with `--edit-format`. | | `--file <path>` | Add a file to Aider's editing scope. Repeatable. | | `--read <path>` | Add a read-only context file. Repeatable. | | `--subtree-only` | Restrict Aider to the current subtree. | | `--read-only` | Dispatch as Aider's `--dry-run`: no files modified. | | `--resume-last` | Restore Aider's chat history for this repo. Send a delta brief. | | `--history-file <path>` | Pin a specific chat history file (Aider's `--chat-history-file`). | | `--timeout <dur>` | Relay watchdog, h/m/s. Default `30m`. | | `--out-dir <dir>` | Where run artifacts go. Default: a fresh dir under the system temp dir. A reused directory has its previous `final.txt` and `result.json` removed before dispatch, so a poller can never read the last run's result as this one's. | Relative `--file`, `--read`, and `--history-file` paths resolve against `--cd`, not the relay's own cwd, so they mean what they look like they mean regardless of flag order. ### Local and self-hosted endpoints `--api-base` points Aider at any OpenAI-compatible server - llama.cpp's server, Ollama, vLLM, LM Studio - so a delegated run can go to a model on the user's own hardware: ```bash node "<skill-dir>/scripts/relay.mjs" --brief brief.txt --cd /path/to/repo \ --model openai/<served-model-name> --api-base http://127.0.0.1:<port>/v1 \ --edit-format whole --file src/target.py ``` The `openai/` prefix selects the protocol, not a provider catalog entry; the name after it is whatever the server reports. Export any non-empty `OPENAI_API_KEY` - the client library requires the header even when the server ignores its value. `--edit-format whole` is the usual choice for smaller local models, which frequently cannot produce the exact search/replace blocks Aider's default `diff` format needs; pair it with `--file` so whole-file rewrites stay small. A server that is not listening reads as a hang rather than an error: Aider retries the connection until the `--timeout` watchdog fires and the relay reports `status: "timeout"`. Check the endpoint is up before dispatching a long brief. The default `30m` watchdog suits short runs. Implementation briefs routinely need `--timeout 1h` or `2h`; a watchdog that fires mid-edit leaves a partial tree. ## What the relay always passes These are not configurable, and the reason matters: | Flag | Why | | --- | --- | | `--no-auto-commits` | Aider's `--auto-commits` defaults to `True` and would commit its own edits. | | `--no-dirty-commits` | Aider's `--dirty-commits` defaults to `True` and would commit your pre-existing uncommitted work before starting. | | `--no-gitignore` | Aider otherwise writes `.aider*` into `.gitignore` on startup, dirtying the tree. | | `--yes-always` | A headless run cannot answer a confirmation prompt. | | `--no-suggest-shell-commands` | The other half of `--yes-always`. Aider's `--suggest-shell-commands` defaults to `True`, and an auto-confirmed suggestion runs on the host with nobody reading it. This is a blast-radius reduction, not a sandbox. | | `--no-analytics` | No telemetry from a dispatched run. Aider's own `--analytics` default is `random`, which opts some sessions in by itself. | | `--no-check-update` | No version check on a dispatch path. | | `--no-detect-urls` | Aider's `--detect-urls` defaults to `True` and offers to scrape any URL in the message. Under `--yes-always` that offer is auto-accepted, so a URL in the brief becomes an unannounced outbound fetch - and, with Playwright absent, a run that hangs until the watchdog fires. | | `--no-pretty` | Colour codes would corrupt the captured report. | | `--no-stream` | Whole responses; the relay captures text, not a live view. | The first two are why this skill can promise a reviewable diff. If you drive `aider` by hand instead, pass them yourself. ## Artifacts and result fields Everything lands in the run directory (temp by default, so the repo under review stays clean): | File | Contents | | --- | --- | | `brief.txt` | The brief as dispatched - and the file Aider reads via `--message-file`. | | `final.txt` | Aider's report, when one was captured. | | `stderr.txt` | Aider's stderr, streamed through to your terminal as well. | | `result.json` | The structured result, written atomically. | `result.json` speaks `delegate-relay.result.v1`: | Field | Meaning | | --- | --- | | `status` | `completed`, `failed`, `timeout`, `aborted`, or `aider_unavailable`. | | `exitCode` | Aider's exit code, or 128+signal, or 127 when the binary is missing. An exit-0 model/endpoint failure detected in the report is remapped to `1`. | | `signal` | The signal that killed the child, else `null`. | | `aiderVersion` | What `aider --version` reported. | | `finalMessage` | Aider's own report. | | `touchedFiles` | `git status --porcelain` lines. `[]` when the tree is clean, `null` when git cannot report. | | `readOnly` | Whether this was dispatched as a dry run. | | `resumed` | Whether chat history was restored. | | `error` | Present on **every** non-clean outcome, including an ordinary nonzero exit; says what went wrong. | | `stderrTail` | Last stderr lines, on a non-clean outcome. | ## Waiting for completion The relay blocks until Aider exits. Run it under the orchestrator's background-command facility, or background it and poll for `result.json` - it is published atomically via rename, so a poller never reads a half-written file. Completion means the process exited and `result.json` exists. Trust that over any progress display. ## When a run misbehaves - **Exit 2, no result file.** A usage error - bad flag, missing value, empty brief, unparseable `--timeout`. Nothing was dispatched. Fix the command. - **Exit 127, `status: "aider_unavailable"`.** `aider` is not on PATH. Install it, or check that the environment running the relay sees the same PATH you do. - **`status: "failed"` with an endpoint or authentication `error`.** Aider exits 0 even when it never reached a model, so the relay scans the run for Aider's own errors and reports this rather than a false success. It is a configuration problem: check the model name, `--api-base`, and provider key. - **`status: "timeout"`.** The watchdog fired and the process tree was killed, possibly mid-edit. Inspect `touchedFiles` before re-dispatching; re-run with a longer `--timeout`. - **`status: "aborted"`.** The relay itself was killed and forwarded the kill to Aider. Same caution: the tree may be partial. - **`--read-only` run that changed something.** Aider's `--dry-run` is Aider's promise, not the relay's measurement, so the relay warns when a read-only run leaves changed paths behind. Only the files Aider *generates* are excluded from that check - `.aider.chat.history.md`, `.aider.input.history`, `.aider.llm.history`, and the `.aider.tags.cache.v*` directory - because it writes them even under `--dry-run`. Aider's user-managed settings are deliberately **not** excluded: if `.aider.conf.yml`, `.aider.model.settings.yml`, `.aider.model.metadata.json`, or `.aiderignore` changed during a dry run, that is exactly what the warning is for. Everything, generated or not, still appears in `touchedFiles`, which reports git verbatim. ## Recovering lost work If the orchestrator loses the relay's output, the run directory still has everything: `final.txt` for the report, `stderr.txt` for the failure, `result.json` for the structured facts. Nothing was committed, so the working tree is exactly as Aider left it - `git diff` is the source of truth. ## The commit boundary The relay never runs `git commit`, `git add`, or `git push`, and it disables Aider's own committing. Reviewing and committing are the orchestrator's job, after the gates pass. See [review-and-land.md](review-and-land.md). -
multi-task-queues.md 2.8 KB
# Multi-task queues A queue is several bounded tasks run through the same loop, one after another, with you reviewing between them. It is not a way to dispatch a large task in parallel pieces. ## Run sequentially, one commit per task Dispatch task N, review it, commit it, then dispatch task N+1. The reasons are practical: - **A clean base per task.** Reviewing a diff means reading what this task changed. If two runs edit the tree at once, `touchedFiles` stops telling you who did what. - **Aider's chat history is per-repository.** `--resume-last` restores the history file in the repo, so concurrent runs in one worktree share and clobber it. Genuine parallelism needs separate worktrees, each with its own history. - **Failure stays contained.** A bad task N is one commit to inspect, not a tangle. If you truly need parallelism, use `git worktree` so each run gets its own tree, its own `.aider.chat.history.md`, and its own reviewable diff. ## Carry decided constraints forward Aider starts each non-resumed run with no memory of the previous one. Anything decided in task 1 that constrains task 3 must be restated in task 3's brief: - Names, signatures, and interfaces settled earlier. - Patterns chosen ("we used the repository pattern here, follow it"). - Boundaries that held ("still do not touch migrations/"). A queue that does not carry constraints forward produces N locally-reasonable changes that do not agree with each other. ## Keep a progress file For anything longer than three tasks, keep a small file outside the repo tracking: task, status, commit sha, and any decision that later tasks depend on. ``` 1. reject negative windows done a1b2c3d ValueError, not clamp 2. propagate through scheduler done e4f5g6h callers let it raise 3. document the new behavior pending follow decision from 1 ``` It survives a lost session, and it is what you carry forward into each brief. ## Close with a coherence check Individually-correct tasks can still add up to something incoherent. After the last one, review the whole range as one diff: ```bash git diff <sha-before-queue>..HEAD ``` Look for interfaces that drifted between tasks, duplicated helpers introduced independently, docs that describe an earlier iteration, and dead code left by a later task. Fix the seams before calling the queue done. ## When to stop and ask Stop the queue and go back to the human when: - A task fails twice for the same reason. The brief is wrong, not the implementer. - A task reveals the plan itself was wrong - a later task no longer makes sense. - Correct completion needs a scope change: a `DO NOT TOUCH` file, a public interface, a new dependency. - The queue's assumptions have gone stale because reality moved under it. Finishing a queue on a false premise is worse than stopping in the middle of it. -
review-and-land.md 5 KB
# Review and land Aider's report is a claim. Your review is the verification. The relay hands you a working tree and a report; deciding whether that work is correct, and committing it, is the part you do not delegate. ## Check tests before trusting gates Before believing "all tests pass", confirm the suite actually ran something. A pytest run that collected zero items, a jest run that matched no files, and a green suite are three different things that can look alike in a summary. Check the counts. The same applies to a gate Aider chose for itself. If the brief named `python -m pytest tests/` and the report shows `pytest tests/test_window.py`, that is a narrower gate than you asked for. ## Aider's lint is not your gates Aider's `--auto-lint` is on by default: after editing, it runs a linter and may fix its own complaints, which produces edits that no brief asked for. That is Aider's lint, not your gates. Run yours, and read the lint-driven edits as part of the diff. ## Re-run the gates yourself Run the project's real commands in the working tree, yourself, and read the output. Not because the implementer lies, but because "I ran the tests" and "the tests pass in this tree right now" are different statements, and only the second one is what you are about to commit. If a gate fails, that is a rework loop (below), not a reason to commit and fix forward. ## Read the diff against the brief Start with `touchedFiles` in `result.json`, then read the actual diff: - Every changed file should map to something the brief asked for. - Anything in the `DO NOT TOUCH` list that moved is a stop. - A file you did not expect is worth understanding before it lands - Aider builds a repo map and can pull in files you did not scope. - Aider's own bookkeeping appears in the tree - `.aider.chat.history.md`, `.aider.input.history`, and a `.aider.tags.cache.v*/` directory. Because the relay passes `--no-gitignore`, these show up as untracked entries in `touchedFiles` rather than being hidden by a `.gitignore` Aider wrote itself. They are not part of the change; do not commit them. Aider writes them under `--dry-run` too, so the relay excludes them when deciding whether a read-only run misbehaved. ## The implementer sweep Things worth checking specifically after a delegated run: - **Dangling references.** After a rename or removal, grep for the old name across the repo, including docs, config, and generated code. - **Round-trip migrations.** A migration that applies is half-verified; roll it back too. - **Silent scope creep.** Refactors "while I was in there" are defensible and still need surfacing. - **Tests that assert the implementation.** A test written against the code just written can pass while the behavior is wrong. Read new tests as carefully as new code. - **Swallowed errors.** A `try`/`except` added around the thing the brief asked to fail loudly. ## The commit boundary **Aider edits the working tree; you commit.** The relay disables Aider's auto-commit and dirty-commit defaults precisely so this boundary exists, and it never runs `git commit` itself. Commit only when: 1. The gates pass in the tree you are looking at. 2. The diff matches the brief. 3. Anything unasked-for has been surfaced to the human or reverted. Write the commit message yourself, describing the change as it landed. Aider's report describes what it believed it did. If the working tree was dirty before the run, separate your commit from the pre-existing changes - `git add -p` or explicit paths, never `git add -A` on a tree you did not start clean. ## Rework: send the delta When the gates fail or the diff misses the brief, do not hand-patch the result and call it delegated - you lose the record of what the implementer actually produced. Re-dispatch: ```bash node "<skill-dir>/scripts/relay.mjs" --brief delta.txt --cd /path/to/repo --resume-last ``` `--resume-last` restores Aider's chat history for the repository, so the delta brief should say only what to change now - the failing gate output, the specific correction. Do not resend the original brief. Because that history lives in the repo (`.aider.chat.history.md`), resume is per-worktree. A fresh clone, or a different checkout of the same project, has nothing to resume; send a full brief there. Review the rework the same way. A second run is not more trustworthy than the first. ## Surface, do not absorb Once the human has opted into delegation, committing verified, gate-passing work is the agreed contract - you do not need to ask again for each task. Two things still go back to them: - **Design decisions the brief did not specify.** Aider chose a name, a structure, an approach. Say so, briefly, in your report. - **Defensible-but-unasked turns.** The extra refactor, the added helper, the reformatted file. And one thing stops the loop entirely: **a scope change**. If completing the task correctly requires going beyond the brief - touching a `DO NOT TOUCH` file, changing a public interface, adding a dependency - ask. Do not expand the mandate on the implementer's behalf. -
writing-the-brief.md 5.5 KB
# Writing the brief The brief is the whole contract. Aider sees the text you send plus the files in its editing scope - nothing else. No chat history, no shared context, none of the reasoning that led you here. Anything you leave implicit, Aider will decide for itself. Write it as if for a competent contractor who has never seen the project. ## Model choice and resumed runs Aider uses its own configured model unless you pass `--model <name>`. For an OpenAI-compatible endpoint, pair it with `--api-base <url>`; a local server usually still needs a placeholder `OPENAI_API_KEY` in the environment because the client requires the header. On a resumed run (`--resume-last`), Aider restores its chat history for the repository, so send only the **delta** - what to change now, not the original brief again. That history lives in the repo (`.aider.chat.history.md`), so it is per-worktree: a fresh clone resumes nothing. ## The shape that works ``` GOAL One sentence. What is true when this is done. CONTEXT Where the code lives, what currently happens, why it is wrong. Point at the files that matter. Name the ones you already ruled out. CHANGE The specific edits you want, in order. Be concrete about names and signatures you have already decided; say "your call" where you have not. DO NOT TOUCH Files, modules, behaviors, and public interfaces that must not move. Migrations, generated files, and vendored code belong here by default. GATES The project's real commands. Aider should run these and report results. REPORT What to tell me when done (see below). ``` ## Scope the files explicitly Aider builds a repo map and pulls in files it thinks are relevant, which is useful for discovery and risky for a bounded task. Two relay flags aim the run: - `--file <path>` puts a file in Aider's **editing** scope. Repeatable. - `--read <path>` supplies a file as **read-only context**. Repeatable. Use `--read` for the interface, schema, or example the change must conform to, and `--file` for what should actually change. `--subtree-only` restricts Aider to the current subtree of the repository. **These are chat-context controls, not a security boundary.** They decide what Aider starts with, and what you pay for in tokens - they do not confine what the run can reach. Aider has no sandbox, the relay dispatches it with `--yes-always`, and a run that decides it needs another file is not stopped by their absence. Treat them as aim, not as a fence. When a change genuinely must not be able to touch something, the boundary has to come from outside Aider: a container, a VM, or a throwaway `git worktree` holding only what the task may see. Scoping the dispatch also does not replace a `DO NOT TOUCH` section - state the boundary in the brief too, because the brief is what Aider reasons about, and then verify it in the diff rather than assuming it held. ## Always ask for the report explicitly Aider will not volunteer a structured summary. Ask for one: ``` REPORT - What you changed, file by file, and why. - Which gates you ran and their exact output. - Anything you decided that I did not specify. - Anything you could not do, and what blocked you. ``` ## Discover the real gates Read the project's config before writing the brief - `package.json` scripts, `Makefile`, `noxfile.py`, `pyproject.toml`, the CI workflow. Name the actual commands. A brief that says "run the tests" against a project whose suite needs a service container produces a confident report and no verification. Aider's own `--auto-lint` runs a linter after edits by default; that is Aider's lint, not your gates. State your gates anyway. ## Honor repo conventions If the project has a `CONVENTIONS.md`, a style guide, or a `CLAUDE.md`/`AGENTS.md`, pass it with `--read` and say in the brief that it is binding. Aider follows conventions it can see. ## One task per brief One goal per dispatch. Bundled tasks produce a diff you cannot review cleanly, and a failure in one half strands the other. Queue them instead - see [multi-task-queues.md](multi-task-queues.md). ## Premises freeze at dispatch Everything you assert in the brief is frozen the moment you dispatch. If you learn something that changes the premises while the run is in flight - a gate command was wrong, an interface moved - do not let the run land on a false basis. Stop it, or discard the result and re-dispatch with the corrected brief. ## A worked example ``` GOAL `parse_window()` should reject a negative duration instead of silently clamping it to zero. CONTEXT src/chronal/window.py, parse_window() around line 40. It currently does max(0, seconds), which turns "-5m" into a zero-length window and makes the scheduler fire immediately. Callers in src/chronal/schedule.py assume a positive window. CHANGE - Raise ValueError("window must be positive") for a non-positive duration. - Leave the parsing of the h/m/s string itself alone. - Update the two call sites in schedule.py to let the error propagate; do not add a try/except that swallows it. DO NOT TOUCH - The duration grammar or its regex. - Anything under migrations/ or tests/fixtures/. GATES - python -m pytest tests/test_window.py tests/test_schedule.py - python -m ruff check src/ REPORT File-by-file summary, exact gate output, decisions I did not specify, and anything you could not do. ``` ## Brief delivery The relay writes your brief to `brief.txt` in the run directory and passes it to Aider with `--message-file`. It never rides argv, so there is no process-list exposure and no OS argument size cap to work around: a long brief is fine. Large *context* still belongs in files Aider reads, not inlined into the brief.
-
-
scripts
-
relay.mjs 34.3 KB · in bundle
-
-
SKILL.md 11.8 KB
--- name: aider-delegate description: >- Delegate a coding task to Aider (`aider`) as a background implementer, then review its diff and land it yourself. Use this whenever the user wants to hand implementation work to Aider - phrasings like "have Aider do X", "delegate this to aider", "run it through Aider", or "use Aider to implement/fix/refactor" - or wants to run a queue of coding tasks through Aider while staying the reviewer. This includes asking Aider to drive a local or self-hosted OpenAI-compatible endpoint ("have Aider use my local model", "run Aider against llama.cpp / Ollama / vLLM / LM Studio"), which Aider reaches via `--api-base`. DO NOT USE for local-model or coding requests that do not name Aider, for tasks small enough to do inline, or when the user wants the code written directly without delegating. license: MIT compatibility: Requires the `aider` CLI (`python -m pip install aider-chat`), Node 18+, and git. Aider must be able to authenticate to a model before dispatch - export the provider key it expects (`OPENAI_API_KEY`, `ANTHROPIC_API_KEY`, …) or set it in Aider's own config; a local OpenAI-compatible endpoint still needs a non-empty `OPENAI_API_KEY`. The orchestrating agent must be able to run shell commands and read files. Shell examples assume bash/zsh (macOS/Linux, or Git Bash/WSL on Windows). metadata: version: 0.5.0 --- # Aider Delegate You are the **orchestrator**. Hand a bounded coding task to a separate **implementer** - Aider - then review what it produced and land it yourself. You write the brief and own the judgment; Aider does the typing in its own run; you verify and commit. The loop needs only a shell command and file access, so any comparable orchestrator can drive it. ## The one thing to know about Aider **Aider commits by default.** Two of its defaults would destroy the reviewable diff this skill exists to produce: - `--auto-commits` (default `True`) - Aider commits its own edits after each exchange. - `--dirty-commits` (default `True`) - Aider commits **your** pre-existing uncommitted work before it starts editing. The relay always passes `--no-auto-commits` and `--no-dirty-commits`, and neither is configurable through it. If you ever drive `aider` by hand instead of through the relay, pass both yourself, or the work lands as commits you never reviewed. The relay also passes `--no-gitignore`, because Aider otherwise writes `.aider*` into `.gitignore` on startup and dirties the tree you are about to read. ## When NOT to use this - The task is small enough to do inline; delegation overhead is not worth it. - The `aider` CLI is not installed, or no model is configured for it. - You want the implementer to manage its own commits. Aider can, but this skill deliberately turns that off - the diff is the deliverable. ## Prerequisites (check once) 1. Install Aider - `python -m pip install aider-chat`, or the standalone installer from the [Aider install docs](https://aider.chat/docs/install.html). 2. Configure a model. Aider reads provider keys from the environment (`OPENAI_API_KEY`, `ANTHROPIC_API_KEY`, …) or its own config; see [Aider's model docs](https://aider.chat/docs/llms.html). 3. Confirm `aider --version` succeeds. 4. Work in, or point `--cd` at, the target git repository. ## Choose the model Aider uses its own configured model when `--model` is omitted. Pass `--model <name>` to pick another. ## Local and self-hosted models Aider talks to any OpenAI-compatible endpoint, so this is also the skill for delegating to a model running on the user's own hardware - llama.cpp's server, Ollama, vLLM, LM Studio, or anything else that serves the same API. Pair `--model` with `--api-base`: ```bash node "<skill-dir>/scripts/relay.mjs" --brief brief.txt --cd /path/to/repo \ --model openai/<served-model-name> --api-base http://127.0.0.1:<port>/v1 ``` Three things differ from a hosted provider: - **The `openai/` prefix is required.** It tells Aider to speak the OpenAI protocol to your endpoint; the part after it is whatever name your server reports, not a provider catalog name. - **A placeholder key is still needed.** Export any non-empty `OPENAI_API_KEY`. The client library requires the header even when the server ignores its value. - **Ask for a smaller edit format.** Local models often fail Aider's default `diff` format, which requires exact search/replace blocks. `--edit-format whole` trades tokens for reliability; keep the brief's scope tight with `--file` so whole-file rewrites stay cheap. A local endpoint that is not running looks like a hang, not an error: Aider retries the connection until the relay's `--timeout` watchdog fires and reports `status: "timeout"`. Confirm the server is up before dispatching a long brief. ### Staying offline No account or provider registration is involved: Aider is a pip install, the endpoint is yours, and `OPENAI_API_KEY` only has to be non-empty. The relay pins the flags that would otherwise reach the network on their own - `--no-check-update`, `--no-analytics` (Aider's own default is `random`, which opts some sessions in by itself), and `--no-detect-urls`, without which Aider offers to scrape any URL in the brief and `--yes-always` accepts that offer silently. `--no-suggest-shell-commands` closes the remaining path by which a run could reach the network without being asked to. What stays outside the relay's control is the brief itself: instructions that tell Aider to install a package or call an API will still be carried out, and `--auto-lint` runs the repository's own tooling. Offline here means nothing in the dispatch path reaches out on its own - not that a sandbox is stopping it. ## The loop Run these five steps per task. Steps 1, 4, and 5 require judgment; 2 and 3 are mechanical. ### 1. Write the brief Aider sees only the text you send plus the files in its editing scope - no chat history or shared context. Include the goal, current state, what to change, what to leave untouched, the project's **actual** gates, and a report contract. Keep one task per brief. See [references/writing-the-brief.md](references/writing-the-brief.md). ### 2. Dispatch Use the bundled helper. It wraps Aider's headless `--message-file` mode, captures the run, and writes `result.json`. (`<skill-dir>` is the installed folder containing this `SKILL.md`.) ```bash node "<skill-dir>/scripts/relay.mjs" --brief brief.txt --cd /path/to/repo # choose a model: add --model <name> # point at an OpenAI-compatible server: add --api-base <url> # scope the edit surface: add --file <path> (repeatable), --read <path> for context only # dry run, no files modified: add --read-only # continue the previous chat: add --resume-last (delta brief only) # hard time limit (watchdog): add --timeout 2h (the 30m default suits short runs; implementation briefs routinely need 1-2h) # see all options: node .../relay.mjs --help ``` The child process's cwd pins the workspace. The brief is delivered with `--message-file`, so it never rides argv: it stays out of the host process list and clear of the OS argument size cap. The relay writes artifacts under the system temp dir by default and never commits. See [references/dispatch-and-poll.md](references/dispatch-and-poll.md). ### 3. Wait for completion The helper blocks until Aider finishes. Run it with the orchestrator's background-command facility, or background it in the shell and poll for `result.json`. A pre-run usage error exits 2 and writes no result; a missing `aider` exits 127 and writes `status: "aider_unavailable"`. Trust process state and the working tree over a progress display. Completion means the process exited and `result.json` exists. Aider's report is the `finalMessage` field in `result.json` (also printed in full on stdout between the report markers). Aider exits 0 even when it never reached a model, so the relay scans the run for Aider's own endpoint and authentication errors and reports `status: "failed"` when it finds one. Treat a `failed` status with an `error` mentioning the endpoint as a configuration problem, not a coding failure. ### 4. Review - do not trust the self-report Treat Aider's final message and gate claims as claims: - Re-run the project's gates yourself. - Read the diff against the brief, starting with `touchedFiles`. - Run relevant guard skills if installed. - Round-trip migrations and grep for dangling references after removals or renames. Aider's `--auto-lint` is on by default, so it may have already run a linter and fixed its own complaints. That is Aider's lint, not your gates - run yours anyway. See [references/review-and-land.md](references/review-and-land.md). ### 5. Land it The implementer edits the working tree; **the orchestrator commits.** Commit only after the gates pass and the diff holds. If rework is needed, send a delta brief with `--resume-last`, then review again. ## Autonomy and permissions The relay passes `--yes-always`, Aider's own term for auto-confirming every prompt, because a headless run cannot answer one. **Understand what that consents to in advance.** Auto-confirmation applies to every prompt Aider would otherwise raise, and Aider's prompts are not limited to file edits: left at its defaults it also offers to run shell commands it has suggested, and `--yes-always` would accept those with nobody reading them. The relay therefore pins `--no-suggest-shell-commands`, which removes that path. What remains is not a sandbox, and nothing here pretends otherwise. Aider has no permission modes and no isolation: within its file scope it edits freely, and `--auto-lint` (on by default) runs whatever linter the repository configures. A brief that tells Aider to run a command still gets a command run. Delegation is the authorization; if a run must not be able to touch the host, run it in a container or a throwaway worktree, because no flag in this relay will give you that. **File selection is not a security boundary.** `--file`, `--read`, and `--subtree-only` set what Aider puts in its chat context, which is a scoping and token-cost decision. They do not confine what it can reach. See [references/writing-the-brief.md](references/writing-the-brief.md). `--read-only` maps to Aider's `--dry-run`, which performs the run without modifying files. The relay does not independently verify that claim - it reports what `git status --porcelain` shows and warns if a `--read-only` run left the tree changed. `touchedFiles` and the diff, not a flag, are the guarantee. ## Resume Aider has no session ids. Its resume unit is the chat history file it keeps in the repository (`.aider.chat.history.md`), so `--resume-last` maps to Aider's `--restore-chat-history` and `--history-file` pins a specific one. Because that history lives in the repo, resume is per-worktree, not per-user: two clones of the same project do not share it. ## Authorization model Delegation is something the human opts into. Once they have ("run this queue", "proceed"), committing verified, gate-passing work is the agreed contract. Two limits remain: **surface, don't absorb** (report Aider's design decisions, defensible-but-unasked turns, and non-blocking nitpicks) and **stop for scope changes** (if correct completion needs going beyond the brief, ask instead of expanding the mandate). See [references/review-and-land.md](references/review-and-land.md). ## References - [references/writing-the-brief.md](references/writing-the-brief.md) - structure, report contract, real gates, file scope, and delta briefs. - [references/dispatch-and-poll.md](references/dispatch-and-poll.md) - flags, artifacts, `result.json`, polling, and failure recovery. - [references/review-and-land.md](references/review-and-land.md) - review checklist, the commit boundary, and rework through Aider's chat history. - [references/multi-task-queues.md](references/multi-task-queues.md) - sequential queues, constraint carry-forward, progress tracking, and the final coherence pass.
Comments (0)
Sign in to join the conversation.
Reviews (0)
No reviews yet.
No comments yet.