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:
@@ -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 1–4 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`.
|
||||
Reference in New Issue
Block a user