feat: e2e acceptance script, README and fleet handoff docs

- scripts/e2e-acceptance.sh: offline spec walk (fixture upstream -> vendor
  add/determinism/collisions/renames -> validate/list/inspect -> update
  cycle -> employee sync -> idempotence -> protected sync -> deletions ->
  status drift -> unreachable repo), 61 assertions on tree, lockfile,
  manifest and exit codes
- README: installation, curator guide (selection rules, renames), client
  guide (three-state semantics, notifications), security model,
  troubleshooting, scope
- docs/fleet-handoff.md: rollout (pinned release, admin-protected config,
  user-context scheduled task), token rotation, ADR draft superseding the
  exact-mirror doctrine, fleet verification checklist
This commit is contained in:
2026-08-23 10:43:41 +02:00
parent 949a431c4c
commit 67cd4e4737
4 changed files with 561 additions and 0 deletions
+137
View File
@@ -0,0 +1,137 @@
# Fleet handoff — agent-lib v2 rollout
What az-fleet must roll out, and why. This document is written so the fleet
team can implement their role from this file alone.
## What the binary does (and does not do)
`agent-lib` is one static Go binary with two roles:
- **Curator** (maintainer machine): `vendor add/update/diff/remove/list/inspect`
plus `validate` — manages external content inside the company work
repository. Publication = `git commit && git push` by the maintainer.
- **Client** (employee machine): `sync` + `status` — pulls the work repository
and deploys skills/commands/agents into the OpenCode paths. Deploys with
three-state protection: user-modified managed items are skipped with a
warning (never steamrolled), self-created items are never touched,
unmodified items update/remove silently.
The binary handles all content transport itself. It never deploys or merges
MCP fragments — `mcp/` and `external/*/mcp/` stay under controller-side merge
and vault substitution (clone the work repository as before, now including
the external areas).
## Rollout components
### 1. Binary via pinned GitHub release
- Source of truth: GitHub releases of `m3tam3re/agent-lib`.
- Artifacts: `agent-lib_{windows_amd64,linux_amd64,linux_arm64,darwin_amd64,darwin_arm64}`
plus `checksums.txt` (tar.gz archives; windows is a zip).
- Fleet pins an exact release tag (installer-pin pattern already used for
other tools). **No self-update exists in the binary** — binary updates are
exclusively fleet rollouts. Content updates are pulled by the binary itself.
- Verify the checksum during rollout; install to a fixed path
(e.g. `C:\Program Files\agent-lib\agent-lib.exe` / `/usr/local/bin/agent-lib`).
### 2. Admin-protected client config
Path: `C:\ProgramData\agent-lib\config.json` (Windows, ACL restricted to
Administrators + read for Users) or `/etc/agent-lib/config.json` (Linux,
root-owned, mode 0644).
```json
{
"repo_url": "https://git.example.com/company/agent-content.git",
"ref": "main",
"token": "<read-only deploy token>",
"token_user": "oauth2"
}
```
- The token is a **shared read-only** deploy token scoped to the work
repository. It is used for HTTP basic auth only and never appears in the
lockfile, the manifest, logs, or error output.
- Employees must be able to read the config (sync runs in their context) but
must not be able to alter it.
- Per-run overrides for testing: `--config <path>` or `AGENT_LIB_CONFIG`.
Local state (manifest, cached bare repo, sync log) lives per-user:
`%LocalAppData%\agent-lib` on Windows, `~/.local/state/agent-lib` on Linux
(override with `AGENT_LIB_STATE_DIR`).
### 3. Scheduled task — logged-in user context (required)
- Schedule `agent-lib sync` per user, **running as the logged-in user, not
SYSTEM**. Two reasons:
1. Deployment targets (`~/.agents/skills`, `~/.config/opencode/...`) resolve
against the user's profile.
2. Windows toast notifications require an interactive user session. A task
running as SYSTEM produces no visible toasts.
- Suggested cadence: every 14 hours plus/except at logon. Sync is idempotent
and cheap when unchanged.
- Optional companion: a drift check running `agent-lib status --json`
headless; its non-zero exit (`problematic_drift: true`) means a user's local
modifications are blocking company updates — feed it into monitoring.
## Token rotation procedure
1. Create/rotate the read-only deploy token on the git host.
2. Update `token` in the admin-protected config via the fleet (single run;
config is fleet-managed, so this is one playbook task).
3. No client-side action: the next scheduled sync picks up the new token
(config is read on every run). The old token can be revoked once the
fleet run completed.
4. A failed sync never damages local state — a revoked token mid-rotation
only means "no updates until the config arrives".
## ADR draft — superseding the "exact mirror" doctrine
> # ADR-000X: agent-lib three-state sync supersedes exact-mirror deletion
>
> ## Status
> Proposed (supersedes ADR-0006 "exact mirror including deletion")
>
> ## Context
> The previous fleet doctrine required employee machines to be an exact
> mirror of the company content repository, including deletions. This
> steamrolled legitimate local work: employees' own skills and their local
> adjustments to company skills were destroyed by routine syncs.
>
> agent-lib v2 replaces the mirror sync with a **manifest-based three-state
> sync**: a local manifest records every item agent-lib deployed (name, type,
> origin, revision, content hash), and the planner compares repository,
> manifest and on-disk content per item.
>
> ## Decision
> 1. Managed items that the user modified locally are **skipped** — the local
> version wins, a warning is logged and (on Windows) toasted.
> 2. Items on disk that agent-lib never deployed are **unmanaged** — left
> untouched, reported by `status` as unrecognized.
> 3. Upstream deletions remove only the **unmodified** managed copies;
> modified copies are kept and warned about.
> 4. Everything else (new, changed-unmodified) updates silently; sync is
> idempotent and safe to schedule.
>
> ## Consequences
> - Employee machines are no longer exact mirrors by design; drift is
> visible (`status`, exit code) instead of silently destroyed.
> - "What's in the repo is what I have" holds for everything the user never
> touched.
> - Remediation for blocked updates is a human decision (restore the company
> version by deleting the local copy and re-syncing), not a forced
> overwrite.
> - The controller-side MCP merge is unaffected: it clones the work
> repository (now including `external/*/mcp/`) and continues to own
> activation, merging and vault substitution.
## Verification checklist for the fleet team
- [ ] Pinned binary installed, `agent-lib version` prints the release version.
- [ ] Config at the admin-protected path, readable by users, writable only by
admins; token present.
- [ ] Scheduled task runs as the logged-in user; toast appears when a
modified item is skipped (manual visual check on a Windows client).
- [ ] `agent-lib status` exits 0 on a clean machine, non-zero after editing a
deployed file (self-test).
- [ ] Drift monitoring consumes `status --json``problematic_drift`.