name: gardener
description: Operate the first-tree gardener CLI — an automated maintenance agent that responds to reviewer feedback on Context Tree sync PRs, posts structured verdict comments on source-repo PRs/issues, and (push mode) installs a GitHub Actions workflow that replaces the long-running gardener service with event-driven per-PR sync. Use whenever a task involves reviewing, responding to, or resolving feedback on tree sync PRs, gating source-repo PRs/issues against a Context Tree, or setting up automatic tree-issue creation from a codebase's CI.
Gardener — Operational Skill
This skill is the operational handbook for the gardener product. If you
have not yet loaded the first-tree entry-point skill, load that first —
it explains the toolkit layout and how the four skills relate. This skill
covers how to drive the first-tree gardener CLI.
Onboarding — short user prompts
The expected user onboarding shape is one short message naming a codebase repo and a tree repo, e.g.:
监听
https://github.com/<codebase-repo>这个 repo, tree 是https://github.com/<tree-repo>. update the latest first-tree CLI first, set up gardener + breeze for this scope, the rest of the check are after the onboarding
From that one line, branch on scenarios A–E below to pick the right
setup path, then run Scenario F to smoke-test the full pipeline end
to end. Do not pepper the user with config questions up front —
infer what you can, ask only when the inference is genuinely ambiguous.
Always finish by restarting the breeze daemon with the new
--allow-repo list so notifications flow.
Step 0 — auto-detect the deployment mode
Before picking a scenario, resolve the source repo's permission level so you don't guess push vs pull:
gh repo view <source-slug> --json viewerPermission -q .viewerPermission
ADMIN/MAINTAIN/WRITE→ go to Scenario B (push mode, lower latency, no daemon).READ/TRIAGE/NONE→ go to Scenario C (pull mode, local daemon). The user cannot land a workflow file in the source repo; don't even suggest it.- Command fails (repo not found, not logged in) OR returns
null/empty → stop and ask the user.nullon a public repo usually meansghisn't authenticated (the command "succeeds" but the viewer is anonymous); treat it the same as the fail branch, not as READ.
If the tree repo doesn't exist yet, run Scenario A first, then come back to this step.
The end-to-end pipeline (what onboarding is actually wiring)
Gardener + breeze together form a routing pipeline. Scenarios A–E below each set up some subset of it; this overview is the target state every scenario points at so you can tell the user what they're getting:
source-repo activity (PR merges, new PRs)
│
▼
gardener sync ──► detects drift between source and tree
│
▼ (--open-issues mode, preferred for multi-owner trees)
one tree-repo issue per proposal, assigned to that node's owners
│
▼
GitHub notification fires for each assignee
│
▼
the assignee's breeze (on their own laptop) sees the notification
│
▼
breeze dispatches to the right agent (gardener draft-node)
│
▼
agent opens a tree PR ──► gardener-respond handles review feedback
Key shape — GitHub assignment is the routing table. If gardener
assigns @bingran-you, bingran's breeze picks it up. If it assigns
@serenakeyitan, her breeze does. No central queue, no shared server.
Each person runs their own breeze against their own notifications.
Two handshake points the onboarding must actually verify:
- NODE.md has
owners:frontmatter — without it,sync --open-issuesfalls back to the tree-repo default owner and labels the issueneeds-owner. Fine for demos; not for steady-state routing. - Each owner has breeze running locally with the tree repo in their
--allow-repolist — without it, the assignment notification fires and dies in the void. This is the "connect the pipes" step: you are not done with onboarding until breeze has surfaced at least one real gardener notification.
See Scenario F — try it end-to-end below for the smoke test, then Scenario G — review the draft-node PR for closing the loop.
Scenario A — fresh: no tree repo yet
Detected when the user hasn't given a tree slug, or the slug 404s.
first-tree tree init— scaffold a new tree in cwd.- Create a GitHub repo (
gh repo create ...), push, bind locally. - Populate
.claude/gardener-config.yamlwith the codebase slug undertarget_repos. - Continue with Scenario B or C depending on push access.
Scenario B — user owns the codebase (push mode, preferred)
Step 0 returned ADMIN / MAINTAIN / WRITE for the source repo.
- Confirm
ANTHROPIC_API_KEYis available (ask user to paste into their shell env if not already exported). first-tree gardener install-workflow --tree-repo <tree>inside the codebase repo.- Walk through
skills/first-tree/references/workflow-mode.mdforTREE_REPO_TOKEN+ANTHROPIC_API_KEYsecret setup (audit-log caveats must be surfaced beforegh secret set). - Open the workflow PR for human review.
Scenario C — user does not own the codebase (pull mode)
Step 0 returned READ / TRIAGE / NONE for the source repo, or the user explicitly said they can't push.
Pick a routing mode before running any command:
| Command | What it does | When to use |
|---|---|---|
first-tree gardener sync --open-issues (operator-run) |
Opens one issue per drift proposal on the tree repo, assigned to that node's owners. Breeze on the owner's laptop picks it up → dispatches to gardener draft-node → draft-node opens the fix PR. Today this is an operator-run step — run it manually (or on a cron) from the tree repo; it isn't wired into the gardener start daemon. |
Default for multi-owner trees. This is the only mode that exercises the draft-node dispatch — it uses GitHub assignment as the distributed queue each owner's local breeze pulls from. Scenario F validates this path. |
first-tree gardener start --sync-apply |
Tells the pull-mode daemon's scheduled sync sweep to open one PR directly on the tree repo with all drift fixes batched together. No issue, no assignment step. | Solo trees, quick-sync demos, or when you want drift fixed automatically without the issue-first routing hop. Scenario F does not apply (no assignment step to observe). |
Once you've picked a routing mode:
export ANTHROPIC_API_KEY=...in the shell that will start the daemon (launchd inherits env at bootstrap time, not at run time).- Start the gardener daemon from inside the tree repo:
- issue-first routing:
first-tree gardener start --tree-path . --code-repo <source> --assign-owners(then runfirst-tree gardener sync --open-issuesmanually or on a cron) - batched PR routing:
first-tree gardener start --tree-path . --code-repo <source> --assign-owners --sync-apply
- issue-first routing:
- Start breeze with the full allow-list:
Thefirst-tree breeze start --allow-repo <tree-slug>,<source-slug>--allow-repoflag is required — breeze silently scans nothing without it. If the daemon is already running with a different allowlist,first-tree breeze startnow fails loudly (#293); stop it first (first-tree breeze stop) then re-start with the merged csv. first-tree gardener status+first-tree breeze statusto confirm both are live, then run Scenario F to watch the full chain execute on a real (or synthetic) drift.
No watch-subscription requirement for routing. Breeze uses
/notifications?participating=true(per #290), so the tree-repo issue's assignee receives the notification directly from the assignment — they don't need to Watch the tree repo. Watching a third-party source repo you aren't directly participating on is a no-op under this filter. Pull-mode gardener itself doesn't consume GitHub notifications;gardener syncpolls source activity viaghdirectly on its own schedule.
Scenario D — add a repo to an existing setup
Detected when ~/.gardener/config.json already exists or target_repos
in the tree's gardener-config.yaml is non-empty.
- Append the new slug to
target_reposin.claude/gardener-config.yaml. - Push mode: run
install-workflowin the new codebase if the user owns it; pull mode:gardener stop && gardener startwith the added--code-repo.
Scenario E — reset / something broken
User describes missing comments or stale notifications.
gardener status+ tail the latest log under~/.gardener/logs/.- Verify
ANTHROPIC_API_KEYis in the launchd plist (plutil -p ~/.gardener/launchd/com.first-tree.gardener.<user>.plist). gardener stop && gardener start ...with the same args. Restart breeze withbreeze start --allow-repo ...after.
Scenario F — try it end-to-end (the "connect the pipes" step)
Runs after A/B/C/D so the user can watch one full cycle execute: drift detected → issue filed on tree → breeze notification → draft-node dispatch → fix PR opened → Scenario G review. Don't skip this on the first onboarding — it's the only way to verify routing actually works before the user walks away thinking it does.
The chain Scenario F proves is wired:
source drift → [gardener sync] → tree-repo issue → GitHub notification
→ [owner's breeze] → [gardener draft-node] → tree-repo PR → Scenario G
Every arrow is a place that can silently drop the message. Each step below names the checkpoint so you know exactly where the break is.
- Preconditions —
TREE_REPO_TOKENset on the shell; at least one NODE.md in the tree hasowners:frontmatter naming a GitHub login; breeze is installed on the laptop owned by that login; that breeze has both the tree and source repos in its--allow-repolist. No GitHub watch subscription is required — the assignee receives a participating notification from the assignment itself. - Seed a synthetic drift — if no real drift exists, make a small change in the source repo and land it (a merged PR with a commit message that mentions something not yet in the tree is enough).
- Dry-run the sync in the tree repo:
Expect:cd <tree-path> first-tree gardener sync --open-issues --dry-runwould open issue on <tree-slug>: "[gardener] <title>"with the right assignees listed. If it says[needs-owner], the affected node'sowners:frontmatter is empty — fix that first, or the routing step (5) has nowhere to go. - Run it for real:
Expect:first-tree gardener sync --open-issues✒ opened issue on <tree-slug>: <url> (assignees: @<login>). Open the URL in the browser and confirm the assignees match the NODE.md frontmatter. Checkpoint: the issue exists on GitHub with a<!-- gardener:sync-proposal ... -->marker in the body and a### Proposed node contentsection. - Watch breeze deliver the notification — on the assignee's laptop,
within the poll interval (default 30s),
~/.breeze/inbox.jsongets a new entry for the issue and the Claude Code statusline announces it. Checkpoint:first-tree breeze inboxlists the new issue. If nothing appears: checkfirst-tree breeze status, confirm the--allow-repolist, confirmgh auth statususer matches the assignee. - Let the draft-node dispatch run — breeze reads the issue body,
sees the
<!-- gardener:sync-proposalmarker, and invokes
under the hood. draft-node copies thefirst-tree gardener draft-node --issue <n> --tree-repo <slug>### Proposed node contentinto the tree at the right NODE.md path and opens a PR namedfirst-tree/draft-node-<proposal_id>against the tree repo. Checkpoint: a new PR exists on the tree repo, linked from the issue (Closes <tree-slug>#<n> on merge.), and breeze has labeled the issuebreeze:done. See Scenario G for what that PR looks like and how to review it.
If any step fails, the pipeline isn't connected — fix that step before
telling the user onboarding is done. The most common breaks are (a)
breeze isn't running with the tree repo in --allow-repo, (b) the
NODE.md has no owners:, or (c) the assignee's gh auth status login
doesn't match the login in owners:.
Scenario G — review the draft-node PR (close the loop)
After Scenario F lands, a tree PR branch named
first-tree/draft-node-<proposal_id> appears on the tree repo. This is
where the human reviews the machine-drafted NODE.md before it merges.
- Open the PR — the breeze task comment links to it; otherwise list
the tree repo's open PRs and look for a
[gardener] draft <node>title or afirst-tree/draft-node-<proposal_id>head branch. - Read the diff — the PR body links back to the source issue
(
Closes <tree-slug>#<n> on merge.) and shows the source SHA or source PR. The NODE.md content was copied verbatim from the issue body; draft-node does not synthesize or summarize. - Edit in-place — push fixups to the same branch if the proposal needs correction; do not rewrite the tree by hand in a separate PR. Keeping edits on the draft-node branch preserves the link to the original proposal for later audits.
- Merge — squash-merge via
gh pr merge --squash. The tree issue closes automatically via theClosesdirective. - Re-run sync — next sync of that source SHA should report no drift on that node. If it still does, the proposal didn't address all drift spans; open a fresh proposal rather than amending.
If draft-node skips because the issue body has no ### Proposed node content section (common on merged-PR variants), hand-edit the tree
from the issue's summary links instead.
Always: restart breeze last
After any scenario, restart breeze with the full --allow-repo list so
gardener-filed tree issues and PR comments surface in the Claude Code
statusline. Never use --allow-repo all — it reopens the
2026-04-21 stranger-repo incident.
Two Operating Modes
Gardener supports two deployment shapes that share the same verdict and issue-filing logic:
| Mode | How it runs | When to use |
|---|---|---|
| Push (workflow) | .github/workflows/first-tree-sync.yml in the codebase repo fires per-PR; no daemon. |
You (or your agent) can land a workflow file in the codebase. Lowest latency, zero infra. |
| Pull (daemon) | first-tree gardener start launches a long-running daemon that polls every configured source repo on a timer. |
The codebase repo is third-party or you otherwise can't push workflow files. Also the right choice when you want drift detection (gardener sync) on a schedule. |
Both modes open the same tree-repo issue on merge and post the same
verdict comment shape on open/updated PRs. The only difference is the
trigger. For the push-mode installer + auth + troubleshooting walkthrough,
see ../first-tree/references/workflow-mode.md.
When To Use This Skill
Load this skill when the task involves any of:
- Installing the push-mode sync workflow in a codebase repo (the user owns the codebase and wants event-driven, per-PR tree sync without running a service)
- Responding to reviewer feedback on a Context Tree sync PR
- Posting a structured verdict comment on a source-repo PR or issue that tests cross-domain alignment with a Context Tree
- Opening a tree issue from a merged source PR (so the tree catches up with a decision made in code)
- Running gardener in CI as an automated maintainer
- Diagnosing why gardener skipped a PR (self-review guard, sync-PR filter, opt-out config)
Gardener is designed for agents, not humans. Every subcommand is idempotent and guarded against acting on its own prior comments.
Core Concepts
- Sync PR — a PR opened against a tree repo by automation (commonly
by
first-tree gardener sync) to propagate a decision; gardener'srespondsubcommand fixes these based on reviewer feedback. - Source-repo PR/issue — a PR or issue opened on an application repo
that gardener's
commentsubcommand evaluates against the bound Context Tree and annotates with a structured verdict. - Merged-PR → tree issue — when
commentsees a merged source PR that was never reviewed while open, it can open a tree issue so the tree picks up the decision retroactively. Gated byTREE_REPO_TOKEN. - State marker — gardener embeds state in HTML comments at the top
of its reviews:
<!-- gardener:state · reviewed=<sha> · verdict=… · severity=… · tree_sha=… -->, a siblinglast_consumed_rereviewline, and a siblingquiet_refresh_cidline for rescan fast-path. Parsing is additive — legacy comments without newer fields degrade gracefully. - Self-loop guard — gardener skips any PR where only it has reviewed, so an automated response cannot trigger another automated response.
- Sync-PR filter (for
comment) — gardener does not comment on first-tree sync PRs themselves; userespondfor those.
CLI Commands
Primary (start here — humans)
These are the commands you invoke directly to set gardener up or check on it. Everything else is driven by these, by breeze, or by CI.
| Command | Purpose |
|---|---|
first-tree gardener install-workflow |
Scaffold .github/workflows/first-tree-sync.yml in a codebase repo — the push-mode entry point. Per-PR events drive the sync flow; no daemon required. |
first-tree gardener start |
Launch the pull-mode daemon in the background. Writes ~/.gardener/config.json from --tree-path + repeated --code-repo args, then boots a launchd job (macOS) or detached process. Schedules: --gardener-interval (default 5m), --sync-interval (default 1h). --assign-owners and --sync-apply wire their downstream flags. |
first-tree gardener stop |
Tear down the launchd job (macOS) or SIGTERM the PID in ~/.gardener/state.json. Idempotent. |
first-tree gardener status |
Print the recorded PID + uptime, configured schedule, and last outcome + next-due time per sweep. Read-only. |
first-tree gardener run-once |
Run both sweeps inline, no daemon. Useful for cron-style deployments or exercising the pipeline before leaving a daemon running. |
Agent commands (called by the daemon, breeze, or CI — not normally by humans)
These are the units of work. You can still invoke them manually for one-off
runs or dry-runs, but the normal trigger is start, push-mode workflow, or
breeze's notification dispatch.
| Command | Purpose |
|---|---|
first-tree gardener sync |
Detect drift between the tree and its bound source repos. Writes proposals under .first-tree/proposals/, edits tree files, commits to a new branch in the tree repo, and opens a PR labeled first-tree:sync. Phases: --propose detects + writes proposals, --apply also writes new tree files and opens the PR, default is detect-only. Moved from first-tree tree sync. |
first-tree gardener comment |
Review a source-repo PR or issue against the tree and post a structured verdict comment. Scan mode (no --pr/--issue) walks every open PR and issue. The merge→tree-issue branch only fires on a single MERGED PR with a prior gardener marker (single-item invocation), and requires TREE_REPO_TOKEN. Pass --assign-owners to auto-assign NODE owners on the tree issue. |
first-tree gardener respond |
Acknowledge reviewer feedback on a sync PR (Phase 5: real edit orchestrator for parent_subdomain_missing + planner seam — see #160 / #219; unsupported patterns fall back to a placeholder reply). |
first-tree gardener draft-node |
Consume a tree-repo issue carrying the gardener:sync-proposal marker (filed by sync --open-issues or comment on a merged PR), copy the proposed NODE.md onto a deterministic first-tree/draft-node-<proposal_id> branch, and open a tree PR for human review. Invoked by breeze when the assignee is the breeze identity; not typically run by hand. Requires TREE_REPO_TOKEN. |
first-tree gardener daemon |
Foreground loop invoked by start. Not intended for direct human use. |
For full options on any command, run first-tree gardener <command> --help.
Prerequisites
gardener comment fails closed without a classifier. Before running any
of the scan/single-item/pull/push-mode flows below, provision:
ANTHROPIC_API_KEY— required for every shipped automation path. Without it the stock CLI refuses to post verdicts and exits 0 withBREEZE_RESULT: status=skipped summary=no classifier injected.GARDENER_CLASSIFIER_MODEL— optional override (defaultclaude-haiku-4-5). Blank values are normalized to the default, so it's safe to leave the GitHub Actions secret unset.
See the per-mode flows below for where each automation entrypoint reads
these vars (shell env for scan/single-item/run-once, launchd plist
for pull-mode daemon on macOS, workflow env: block for push mode).
Typical Flows
Scan mode — review every open PR/issue across all bound source repos
export ANTHROPIC_API_KEY=sk-... # required
# export GARDENER_CLASSIFIER_MODEL=... # optional; default claude-haiku-4-5
npx -p first-tree first-tree gardener comment
Run from inside a tree repo. Reads .claude/gardener-config.yaml, then
walks every open PR and issue on every configured source repo
(target_repo scalar + target_repos list, deduped), posting structured
verdict comments against the tree. Results are aggregated into a single
BREEZE_RESULT trailer with repos=<n>. Without ANTHROPIC_API_KEY
the stock CLI skips the sweep (status=skipped summary=no classifier injected) and does not call gh.
Scan mode with merged-PR sweep
npx -p first-tree first-tree gardener comment --merged-since 24h --assign-owners
Same as scan mode but also fetches PRs merged within the window (e.g.
1h, 24h, 7d, or an ISO-8601 timestamp) and routes them through the
same reviewer. Merged PRs with a prior gardener marker take the
merge→tree-issue branch when TREE_REPO_TOKEN is set — this is how the
gardener pull-mode daemon catches post-merge events without needing
GitHub webhooks. Without --merged-since, scan mode looks at open items
only; the merge→tree-issue branch still fires from single-item
invocations as before.
Single-item mode — one PR or issue
npx -p first-tree first-tree gardener comment --pr 42 --repo owner/app-repo
npx -p first-tree first-tree gardener comment --issue 7 --repo owner/app-repo
The single-item form is what breeze-runner calls when dispatching on a
notification. Skips the scan; reviews exactly the one item. Also takes
the merge→tree-issue branch when pointed at a single MERGED PR with a
prior gardener marker and TREE_REPO_TOKEN set. ANTHROPIC_API_KEY
must be present in the invoking shell or the run exits early with
status=skipped summary=no classifier injected.
Pull-mode daemon — monitor many code repos on a schedule
Use this when push-mode workflows aren't an option or when you want
drift detection (gardener sync) to run on a timer in addition to
per-PR verdict comments.
export ANTHROPIC_API_KEY=sk-... # required; forwarded into launchd plist
# export GARDENER_CLASSIFIER_MODEL=... # optional override
# 1. Bind the tree checkout first (if not already): `first-tree tree bind`
# 2. Start the daemon pointed at the tree + the code repos to watch.
npx -p first-tree first-tree gardener start \
--tree-path ../my-org-tree \
--code-repo my-org/web --code-repo my-org/api \
--gardener-interval 5m \
--sync-interval 1h \
--assign-owners
What happens:
~/.gardener/config.jsonis written with the supplied schedule.- On macOS, a launchd plist
com.first-tree.gardener.<user>.plistlives at~/.gardener/launchd/and is bootstrapped into the user domain.ANTHROPIC_API_KEYand (if set)GARDENER_CLASSIFIER_MODELfrom the invoking shell are forwarded into the plist'sEnvironmentVariablesdict — launchd does not inherit shell env, so these must be exported beforegardener start. On other platforms, a detached child process is spawned with the full parent env. - The daemon ticks every
30 s. Each tick checks whether/.gardener/state.json`.gardener-sweeporsync-sweepis due and runs it as a subprocess (gardener comment --merged-since 2×intervalandgardener syncrespectively). Outcomes get written to `
Inspect and tear down:
npx -p first-tree first-tree gardener status # last runs + next due
npx -p first-tree first-tree gardener run-once # fire both sweeps inline
npx -p first-tree first-tree gardener stop # launchctl bootout + SIGTERM
Set --sync-apply on start to have sync-sweep open tree PRs
automatically (gardener sync --apply); without it, the sweep stays in
detect-only mode.
Install the push-mode workflow in a codebase repo
Agent-driven path. Before running anything, walk the user through the
preflight in ../first-tree/references/workflow-mode.md
(confirm consent, tree-repo slug, codebase-repo slug). Then:
npx -p first-tree first-tree gardener install-workflow \
--tree-repo <OWNER>/<TREE_REPO_NAME>
Set the TREE_REPO_TOKEN secret (see the workflow-mode reference for
the quick gh auth token path and its caveats, or the scoped-PAT
fallback) and the ANTHROPIC_API_KEY secret on the codebase repo —
the generated workflow references both via
secrets.ANTHROPIC_API_KEY / secrets.TREE_REPO_TOKEN and falls back
to a skip if the classifier key is missing. GARDENER_CLASSIFIER_MODEL
is wired through as an optional secret; leave it unset to use the
default model. Commit the generated workflow file and open a PR. On
every PR merge thereafter the workflow files a tree-repo issue assigned
to the NODE owners.
Respond to feedback on a sync PR
npx -p first-tree first-tree gardener respond --pr 123 --repo owner/tree-repo
Single-PR only. There is no scan mode — discovery for respond lives in
breeze's notification poller. Add --dry-run to preview.
Current behavior (placeholder reply only):
respondbumps the attempts marker and posts an acknowledgement reply, but does not yet editNODE.md, commit, or push. Wiring the real edit orchestrator is tracked in #160 with the Phase 5 scope proposal in #219.
Dry-run everything
Both subcommands accept --dry-run, which prints every planned
gh/git call without executing it. Use this when introducing gardener
to a new repo or verifying config before a live run.
Add --assign-owners to have merged-PR tree issues auto-assigned to
the NODE owners resolved from the tree's CODEOWNERS. Push-mode
workflows set this flag by default; pull-mode deployments can opt in
per-invocation.
Recommended Invocation
npx -p first-tree first-tree gardener <command>
This always runs the latest published version.
Configuration
Gardener reads .claude/gardener-config.yaml from the tree repo
(resolved via --tree-path, default cwd):
# Either form (or both) is accepted. Scan mode sweeps the deduped union
# in source order: scalar first, then list, then any extras the typed
# loader adds. Pick scalar when binding one source repo, list for fan-out.
target_repo: owner/app-repo # source repo to review (scalar)
target_repos: # source repos to review (list)
- owner/app-repo-frontend
- owner/app-repo-backend
tree_repo: owner/tree-repo # this tree repo (for attribution links)
modules:
comment:
enabled: true # set false to opt the tree out entirely
respond:
enabled: true
The modules.<name>.enabled: false knob is the opt-out: gardener exits
0 with a skipped status without calling gh.
Environment
Gardener reads a small set of env vars. ANTHROPIC_API_KEY is required
for every gardener comment invocation; TREE_REPO_TOKEN is required
only for the merge→issue branch.
| Variable | Purpose |
|---|---|
ANTHROPIC_API_KEY |
Required for gardener comment. The stock CLI instantiates the built-in Anthropic classifier from this key; if it is unset, runComment fails closed and emits BREEZE_RESULT: status=skipped summary=no classifier injected without touching gh. Forwarded into the launchd plist by gardener start; referenced as secrets.ANTHROPIC_API_KEY by the push-mode workflow generated by install-workflow. |
GARDENER_CLASSIFIER_MODEL |
Optional override for the classifier model (default claude-haiku-4-5). Blank/unset is normalized to the default, so it's safe to leave the GitHub Actions secret empty. |
BREEZE_SNAPSHOT_DIR |
Directory with pre-fetched pr-view.json, pr.diff, issue-view.json, issue-comments.json, pr-reviews.json, subject.json. Set by breeze-runner so gardener doesn't re-fetch. Also enables snapshot-mode idempotency checks in respond when pr-commits.json is present. |
TREE_REPO_TOKEN |
PAT with repo scope on the tree repo. Consumed only by comment's merge→issue branch, for gh issue create and the follow-up marker PATCH. No fallback to GH_TOKEN/GITHUB_TOKEN — if unset, the merge→issue path silently skips and logs skipped: token_absent. |
COMMENT_LOG |
Path for JSONL run events from comment (default $HOME/.gardener/comment-runs.jsonl; falls back to $TMPDIR when HOME is unset). |
RESPOND_LOG |
Same shape for respond (default $HOME/.gardener/respond-runs.jsonl). |
Guards And Idempotency
Gardener refuses to act when:
ANTHROPIC_API_KEYis unset (no classifier injected —commentexits 0 withstatus=skipped summary=no classifier injectedbefore callinggh)- Only it has reviewed the PR (self-loop guard) — prevents infinite response loops
- The target PR is itself a
first-tree:syncPR on a tree repo — userespondthere, notcomment - The module is disabled in
.claude/gardener-config.yaml - Required inputs (
--pr,--issue,--repo) are missing TREE_REPO_TOKENis unset on the merge→issue branch (skips that branch; other branches continue)
All subcommands are safe to re-run. Idempotency lives in the state
marker: the SHA in reviewed=<sha> tells gardener whether a PR has
already been reviewed at this revision, and the tree_issue_created=<url>
field prevents duplicate issue creation on a retry.
Related Skills
first-tree— entry-point skill: methodology, references, routing. Load this first.tree— load if the task also requires direct reads or writes against the tree repo (gardener operates on PRs; tree tools operate on the tree itself).breeze— load if gardener is being invoked from the breeze daemon's dispatch pipeline rather than manually.