Skip to content

Commit 1d69ac7

Browse files
endolinbotclaude
andcommitted
onboarding phase 2: author the context/ operator tree
Add the context/ tree (main2) — the garden's on-demand operations manual for agents, per designs/streamlined-onboarding.md §§ 3, 3.1, 3.2, 4. Twelve files: a routing top README, first-run/ (the guided tutorial track: README with the ordered stage list + interaction norms, plus identity/auth/first-job leaves) and operations/ (day-2 routing README plus starting/leader-follower/scaling/ deploy/schedules/health leaves). Each leaf opens with an exit-criterion abstract; content migrated from README.md and CLAUDE.md §§ Job system / Host environment per § 4 (sources left intact — phase 4 trims them). Amend skills/context-library/SKILL.md's scope line to declare it canonical for context/ on main2 as a second canonical tree (same discipline, different branch), rather than forking the discipline. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
1 parent 8fdbd11 commit 1d69ac7

13 files changed

Lines changed: 767 additions & 6 deletions

File tree

context/README.md

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
# context/ — the garden's operations manual for agents
2+
3+
This tree is the garden's **operator procedure for agents**, read on demand by
4+
the liaison — never auto-loaded. It answers two questions: how do I walk a
5+
brand-new user through their first run (`help`), and how do I operate a running
6+
instance day to day (`help <topic>`). It ships with the code on `main2`, so the
7+
procedure and the scripts it drives version together. If your query is "what
8+
command does X" or "walk the user through Y," it is here or one hop away; if it
9+
is "why is the machinery shaped this way," that is `designs/`, and this tree
10+
routes you there rather than repeating it.
11+
12+
What this tree does **not** hold: per-instance state or history (that is the
13+
journal, `journal2`); architectural rationale (that is `designs/`); imported
14+
material (that is `references/`); and procedures already encoded as skills —
15+
where a skill owns a procedure (restore, schedule, job-board), the page here
16+
**routes to it** and adds only the operator's framing. See
17+
`skills/context-library/SKILL.md` for the authoring discipline this tree obeys,
18+
and `designs/streamlined-onboarding.md` for why it exists.
19+
20+
## Children
21+
22+
- **[first-run/](first-run/README.md)** — the guided first-run tutorial the
23+
liaison drives when a user says **help** on a not-yet-armed instance: an
24+
ordered, conversational stage list (welcome → identity → bot credentials →
25+
starting the garden → first job → where next) plus the interaction norms that
26+
bind the liaison driving it. Read here to run the tour or to answer a
27+
first-run question (identity, auth, posting a first job).
28+
29+
- **[operations/](operations/README.md)** — day-2 procedure, picked by symptom
30+
or intent: starting the garden at command level, leader/follower on multiple
31+
hosts, scaling the pool, the deliberate deploy, schedules, and health. Read
32+
here to *do* an operation on a running instance, or to answer `help <topic>`
33+
for an operator.
34+
35+
## Convention
36+
37+
Cross-references **within** this tree are relative (`first-run/identity.md`,
38+
`../operations/starting.md`). Cross-references to **other** trees — skills,
39+
designs, roles, the top-level READMEs — are repo-root paths
40+
(`skills/restore/SKILL.md`, `designs/multibot-leader-follower.md`). A new
41+
operational topic lands as a new leaf with a row in the nearest directory
42+
README; split a directory only when its README stops routing cleanly.

context/first-run/README.md

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
# first-run/ — the guided first-run tutorial
2+
3+
The ordered, conversational track the liaison drives when a user says **help**
4+
on a not-yet-armed instance. This README **is** the tutorial script: it lists
5+
the stages in run order with a one-line abstract each, and it carries the
6+
**interaction norms** that bind the liaison driving it. There is deliberately no
7+
separate tutorial script to drift from — this ordered tree is the single source
8+
of truth, and each stage page is read just-in-time as the liaison reaches it.
9+
Read here to run the tour, to resume a half-finished one, or to answer a
10+
first-run question. Day-2 operation of a running instance is a sibling tree,
11+
`../operations/README.md`.
12+
13+
Bare **help** starts at stage 1 and walks through. **start the garden** jumps
14+
straight to stage 4 (the user who wants motion, not a tour). On an
15+
**already-armed** instance, bare `help` skips the walk and degenerates to a
16+
status summary (units, board counts, leadership, drain state) plus the
17+
`help <topic>` menu — the stage pages double as the topic answers, so nothing
18+
is written twice.
19+
20+
## Interaction norms (binding on the liaison driving the track)
21+
22+
- **Ask before acting, act on approval.** Every mutating step is proposed in one
23+
sentence with the exact command shown, then run **by the liaison itself** on a
24+
yes — never printed for the human to copy. Read-only checks (probes, status
25+
reads) run freely without asking.
26+
- **Verify after each stage** — a unit list, a `gh auth status`, a board read —
27+
and show the one-line result, so trust accumulates stage by stage.
28+
- **Resumable and idempotent.** Every stage begins with its own probe and skips
29+
cleanly when already done, so `help` after a half-finished first run continues
30+
where it left off, and `help` on a healthy instance degenerates to the status
31+
summary.
32+
- **Escalate, don't improvise, on policy.** Stages that touch permissioned
33+
surfaces (watch-set widening, the ferry, identity switches) are *described*
34+
but never *performed* in the tutorial; route to the maintainer-authorization
35+
paths that govern them rather than acting.
36+
37+
## The stages
38+
39+
1. **Welcome.** One paragraph on what the garden is and what the tutorial will
40+
do, ending with "shall we?". No page — it is this framing.
41+
42+
2. **Identity → [identity.md](identity.md).** Confirm we are in-container (the
43+
guard already ran), read `.garden`, and ask the one question only the human
44+
can answer: is this name unique among your running instances? On a collision,
45+
offer the rename and run it on approval.
46+
47+
3. **Bot credentials → [auth.md](auth.md).** Probe `gh auth status` and `.ssh/`.
48+
For missing pieces: generate the bot ssh key, print the public half and wait
49+
while the human adds it to the **bot** account, run `gh auth login` and relay
50+
the device code. Verify by whoami-ing the `gh` wrapper.
51+
52+
4. **Starting the garden → [first-job.md](first-job.md) for the board, and the
53+
command-level substance in `../operations/starting.md`.** The conversational
54+
pivot: on **start the garden** the liaison performs the whole bring-up itself
55+
— linger, install and enable units, size the pool, designate the leader on a
56+
first host, arm its own Monitors, offer the optional armings — asking before
57+
each consequential step and verifying after. The commands live in
58+
`../operations/starting.md` (agent-facing detail the liaison executes on
59+
demand), deliberately **not** here: this stage stays a conversation.
60+
61+
5. **First job → [first-job.md](first-job.md).** Offer to post a small real job,
62+
watch it cross `todo/ → doin/ → tada/`, and read the report back — teaching
63+
the board's shape and the core verbs.
64+
65+
6. **Where to go next.** Point at `help <topic>` (the `../operations/` tree),
66+
the control surfaces, and the README's conceptual §§ 2–3 for the architecture
67+
tour. No page — it is this handoff.
68+
69+
## Children (stage pages)
70+
71+
- **[identity.md](identity.md)** — the `GARDEN` shard identity: the `.garden`
72+
file as the one naming knob, the `GARDEN=… ./garden` convenience form, the
73+
uniqueness requirement, and the rename / parallel-pool moves.
74+
- **[auth.md](auth.md)** — the three credentials (claude login or API key, bot
75+
ssh key, bot gh token): probes, the liaison-run halves, the human-only browser
76+
clicks, and the conservative non-bypass launch variant.
77+
- **[first-job.md](first-job.md)** — posting a first job, the board's states,
78+
and the core verbs with pointers to the vocabulary table.

context/first-run/auth.md

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
# The three credentials
2+
3+
A fresh clone holds no credentials. A working instance needs exactly three, and
4+
each has a **liaison-run half** and an irreducible **human-only click**: the
5+
**claude** login (or an API key), the **bot ssh key**, and the **bot gh token**.
6+
This page is the probes, the halves, and the human moments — plus the
7+
conservative non-bypass launch variant for a user who wants per-command prompts.
8+
All three credentials land in the bind-mounted home and persist across
9+
`./garden reset`. If your question is "how does the bot authenticate" or "why is
10+
`gh` acting as the wrong identity," you are here; the ferry's separate,
11+
maintainer-only human-identity path is `README.md` § The ferry and
12+
`roles/boatman/AGENT.md`.
13+
14+
## 1. Claude auth — inside golden-path step 2, zero extra steps
15+
16+
The exec'd `claude` runs its own first-launch onboarding: pick a login method,
17+
open the printed URL **in a browser on the host** (the container has none),
18+
paste the code back. The credential lands in the bind-mounted home.
19+
20+
- **Beaten path:** a **Claude subscription login** — the whole fleet runs on one
21+
subscription.
22+
- **Alternate path:** export `ANTHROPIC_API_KEY` **before the first
23+
`./garden`**; the launcher forwards it at container creation and the login is
24+
skipped entirely.
25+
26+
Neither is a procedure the human runs by hand — the tool prompts for it. It is
27+
one sentence of residue: "have a Claude subscription or an API key."
28+
29+
## 2. Bot ssh key — liaison generates, human pastes
30+
31+
The launcher deliberately does **not** forward your SSH agent: an
32+
agent-forwarded human identity must not leak into bot actions. The bot uses its
33+
own key under `<garden-root>/.ssh/` (which is `~/.ssh/` inside the container,
34+
gitignored). The liaison's half:
35+
36+
1. Probe `.ssh/` for an existing `id_ed25519`.
37+
2. If absent, generate one and **print the public half**.
38+
3. **Wait** while the human pastes it into the **bot** GitHub account's SSH keys
39+
— the human-only click.
40+
41+
## 3. Bot gh token — liaison runs login, human authorizes
42+
43+
Inside the container, authenticate `gh` as the **bot**:
44+
45+
1. Probe `gh auth status`.
46+
2. If unauthenticated, run `gh auth login` and **relay the device-flow URL and
47+
code** to the human, who opens it and clicks "authorize" — the human-only
48+
click. The token lands in `.config/gh/` (bind-mounted, gitignored).
49+
3. **Verify** by whoami-ing the fleet's `gh` wrapper — it must report the bot
50+
login, not your identity. The wrapper pins every call to the bot; the one
51+
exception is the ferry's explicit `GARDEN_GH_IDENTITY=kriskowal` override
52+
(`designs/fleet-gh-identity.md`).
53+
54+
## The conservative non-bypass launch variant
55+
56+
Bare `./garden` execs the liaison with `--dangerously-skip-permissions` (auto
57+
mode) — matching the fleet's existing headless posture and making the tutorial
58+
usable (prompt-per-command would turn the tour into dozens of nags). The
59+
interactive liaison still **asks before consequential garden operations** per
60+
the tutorial's ask-before-acting contract (`README.md` in this tree, §
61+
Interaction norms).
62+
63+
A user who wants per-command prompts instead of bypass can launch conservatively
64+
via the debug shell:
65+
66+
```sh
67+
./garden sh # today's enter behavior: bash -l, no claude
68+
claude --permission-mode acceptEdits # prompt on non-edit actions
69+
```
70+
71+
Optionally seed a `scripts/jobs/*` allowlist so the routine board commands stop
72+
prompting. This variant is documented, **not defaulted** — auto mode is the
73+
default (`designs/streamlined-onboarding.md` § 1.3). Claude Code's own one-time
74+
bypass acknowledgment (a single keystroke on first launch) stays as the explicit
75+
opt-in moment.

context/first-run/first-job.md

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
# Posting a first job
2+
3+
The last teaching stage: post one small real job, watch it cross the board's
4+
three states, and read the report back — so the user sees the whole
5+
producer→board→worker→report loop once, concretely. This page is how the liaison
6+
posts that first job, what the board states mean, and the core verbs that turn a
7+
sentence of intent into a job. If your question is "how does work reach a
8+
worker" or "what does the board look like," you are here; the full job-board
9+
mechanics (the git-push claim CAS, the per-doer worktrees) are
10+
`skills/job-board/SKILL.md`, and the complete verb list is `README.md` § Key
11+
vocabulary and `CLAUDE.md` § Orchestrator vocabulary.
12+
13+
## Posting the job
14+
15+
The liaison never does the substance itself — it **posts a job to the board**,
16+
and a gardener claims it. The primitive:
17+
18+
```sh
19+
scripts/jobs/post-job.sh <basename> [body]
20+
```
21+
22+
`<basename>` is a short deterministic name derived from the change identity; the
23+
body names the repo, any PR/comment URL, and the task in a sentence or two. For
24+
the tutorial, a tiny self-contained job (a trivial garden-library edit, or a
25+
"say hello and report" job) is enough to demonstrate the loop without waiting on
26+
CI. Post it, then watch.
27+
28+
## The three board states
29+
30+
Every job is a file that moves through three directories on the `journal2`
31+
branch:
32+
33+
- **`todo/`** — posted, unclaimed. Any eligible gardener may race to claim it.
34+
- **`doin/`** — claimed. The accepted `git push` to `origin/journal2` is the
35+
compare-and-swap that serializes the claim: first pusher wins, the rest back
36+
off to another job. The worker runs it in an isolated per-job worktree.
37+
- **`tada/`** — done. The worker's completion report lands here; the follow-up
38+
service reads each report's `## Follow-ups` section and turns actionable ones
39+
into new jobs, so the board feeds itself.
40+
41+
Watch a job cross `todo/ → doin/ → tada/`, then read the report back to the
42+
user. That is the entire life of an issue in miniature (`README.md` § The life
43+
of an issue).
44+
45+
## The core verbs
46+
47+
The user steers in plain language — a sentence of intent becomes a job — but
48+
these verbs are precise shorthand, and the PR-comment watchers recognize the
49+
branch-op ones deterministically:
50+
51+
- **design X** / propose X / spec X — draft a design, open it as a DRAFT PR.
52+
- **build #N** / build X — implement an approved design.
53+
- **run the gauntlet #N** — the full PR chain: clean → panel review → fix-loop →
54+
un-draft.
55+
- **fix #N**, **rebase #N**, **weave #N**, **shepherd #N**, **merge #N** — the
56+
branch-op verbs that unstick and advance a PR.
57+
- **defer X** / park X, **promote X** / go ahead — steer the plan queue.
58+
- **ferry #N** — carry approved work upstream under the maintainer's identity;
59+
authorization required.
60+
61+
The authoritative tables (with what each does and which are watcher-recognized)
62+
are `README.md` § Key vocabulary and `CLAUDE.md` § Orchestrator vocabulary —
63+
point the user there rather than reproducing the full list.

context/first-run/identity.md

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
# The GARDEN shard identity
2+
3+
Every garden instance has one logical name — its **`GARDEN` shard identity**
4+
and it **must be unique across every running instance you own**. It keys job
5+
claims, per-host worker counts (`hosts/<host>`), journal index entries, and the
6+
leader marker; two instances sharing a name silently corrupt each other's
7+
per-host state. This page is the naming knob and the uniqueness discipline: the
8+
`.garden` file as the one place the name lives, `GARDEN=… ./garden` as sugar
9+
over it, why an exported env var does not reach the fleet, and the rename /
10+
parallel-pool moves. If your question is "how do I name this instance" or "these
11+
two instances are stepping on each other," you are in the right place; the
12+
multi-host leader/follower mechanics that the marker gates are
13+
`../operations/leader-follower.md`.
14+
15+
## The one naming knob: `.garden`
16+
17+
The streamlined, preferred way to name an instance is one line **before the
18+
first `./garden`**:
19+
20+
```sh
21+
echo petunias > .garden
22+
```
23+
24+
The launcher reads `.garden` when present and derives the container name and
25+
`--hostname` from it. Bare `./garden` needs **no environment variables** — every
26+
default is satisfactory, and an unnamed instance falls back to the container
27+
hostname. You only name an instance when you run **more than one**.
28+
29+
The convenience form does the same thing through an env var:
30+
31+
```sh
32+
GARDEN=petunias ./garden
33+
```
34+
35+
This sets the container hostname **and** writes `.garden`, so the container is
36+
built and named from that identity either way. The env var is **sugar over the
37+
file**, and the file is the documented default. `GARDEN_CONTAINER` /
38+
`GARDEN_HOSTNAME` remain as expert overrides; `GARDEN_SHARD` is a deprecated
39+
alias for `GARDEN` for one release.
40+
41+
## How the fleet resolves the identity
42+
43+
Every fleet script resolves `GARDEN` as: **`GARDEN` env → the gitignored
44+
`.garden` file → `hostname -s`** (`common.sh`). The durable file exists because
45+
an **exported `GARDEN` does not reach the systemd `--user` units** — they are
46+
started by the user manager, not your shell, so they read the file, not your
47+
environment. That is the whole reason the name is written to disk rather than
48+
left in the environment: set it at container-creation time so it lands in
49+
`.garden`, and every unit sees it.
50+
51+
## The uniqueness check (the human's one answer)
52+
53+
The kernel hostname cannot be changed from inside a container (its capabilities
54+
are zero), so the logical name is **fixed at container creation** via
55+
`--hostname`/`--name` (both `GARDEN_CONTAINER`). During the tutorial the liaison
56+
reads `.garden` and asks the single question only the human can answer: **"is
57+
this name unique among your running garden instances?"** A default or a
58+
collision is the only thing that needs fixing here.
59+
60+
## Rename, and the parallel-pool move
61+
62+
To **rename** an existing instance, reset and re-create it under the new name:
63+
64+
```sh
65+
./garden reset
66+
echo <unique-name> > .garden # or: GARDEN=<unique-name> ./garden
67+
./garden
68+
```
69+
70+
For a **lighter, per-invocation** identity — a second follower pool on the same
71+
machine, launched from a checked-out worktree with no Dockerfile change — just
72+
export `GARDEN=<unique>` for that invocation. Set `GARDEN` at creation only when
73+
a pool's identity must differ from its hostname.
74+
75+
Rationale for the container/hostname coupling and the resolution order lives in
76+
`CLAUDE.md` § Host environment; this page is the operator's how-to.

context/operations/README.md

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
# operations/ — day-2 procedure, picked by symptom or intent
2+
3+
Command-level operator procedure for a **running** instance: everything the
4+
liaison executes on demand after the first run. Pick a child by what you are
5+
trying to do or what is wrong. This tree holds the *how-to*; the *why* is
6+
`designs/`, and each page routes there for rationale rather than repeating it,
7+
and to the owning skill where a skill already encodes the procedure (restore,
8+
schedule). The conversational first-run tour is the sibling tree,
9+
`../first-run/README.md`; the command-level substance behind its
10+
"start the garden" stage lives here in [starting.md](starting.md).
11+
12+
## Pick by intent
13+
14+
- **[starting.md](starting.md)***"start the garden" / bring up a fresh
15+
instance.* Linger, install and enable units, size the pool, designate the
16+
leader on a first host, the liaison's three Monitors and their singleton
17+
rules, and the optional armings (issue inbox, bulletin PAT). This is the
18+
agent-facing detail the liaison runs for tutorial stage 4 and any later
19+
re-start — not a human checklist.
20+
21+
- **[leader-follower.md](leader-follower.md)***"add a second host" /
22+
"hand off leadership" / "which services run where."* Leader-marker semantics,
23+
what runs on followers vs. the leader, follower stand-up, and the
24+
drain→stand-down→re-point handoff. No automatic failover. Routes to
25+
`designs/multibot-leader-follower.md` for rationale.
26+
27+
- **[scaling.md](scaling.md)***"scale up/down" / "pause the fleet."* Sizing
28+
the pool, `set-gardeners` per host, and `drain on/off` — when to prefer which.
29+
30+
- **[deploy.md](deploy.md)***"an upgrade is ready" / "what is the root
31+
checkout."* The deliberate deploy: the upgrade-ready signal, `deploy-garden.sh`,
32+
and why the root checkout is a deployed version, not a dev tree.
33+
34+
- **[schedules.md](schedules.md)***"run something weekly / once at a time."*
35+
Recurring and one-shot schedules. Routes to `skills/schedule/SKILL.md`.
36+
37+
- **[health.md](health.md)***"a unit failed" / "recover after an outage" /
38+
"what are the reaper, deadmail, poison."* Failed-unit checks, the restore
39+
engagement (routes to `skills/restore/SKILL.md`), and the self-healing
40+
services in one paragraph each.
41+
42+
## Convention
43+
44+
Within-tree cross-references are relative; cross-tree references (skills,
45+
designs, roles) are repo-root paths. A new operational topic lands as a new leaf
46+
with a row above; split this directory only when this README stops routing
47+
cleanly.

0 commit comments

Comments
 (0)